The IoC containerIntroductionThis chapter covers the Spring Framework's implementation of the
Inversion of Control (IoC) See the section entitled principle.The org.springframework.beans and
org.springframework.context packages provide the basis
for the Spring Framework's IoC container. The BeanFactory
interface provides an advanced configuration mechanism capable of managing
objects of any nature. The ApplicationContext
interface builds on top of the BeanFactory
(it is a sub-interface) and adds other functionality such as easier
integration with Spring's AOP features, message resource handling (for use
in internationalization), event propagation, and application-layer
specific contexts such as the
WebApplicationContext for use in web
applications.In short, the BeanFactory provides
the configuration framework and basic functionality, while the
ApplicationContext adds more
enterprise-centric functionality to it. The
ApplicationContext is a complete superset
of the BeanFactory, and any description of
BeanFactory capabilities and behavior is to
be considered to apply to the
ApplicationContext as well.BeanFactory or
ApplicationContext?Users are sometimes unsure whether a
BeanFactory or an
ApplicationContext is best suited for use
in a particular situation. A BeanFactory
pretty much just instantiates and configures beans. An
ApplicationContext also does that,
and it provides the supporting infrastructure to
enable lots of enterprise-specific features such as
transactions and AOP.In short, favor the use of an
ApplicationContext.(For the specific details behind this recommendation, see this
section.)This chapter is divided into two parts, with the first part covering the basic principles
that apply to both the BeanFactory and
ApplicationContext, and with the second part covering those features
that apply only to the ApplicationContext
interface.Basics - containers and beansIn Spring, those objects that form the backbone of your application
and that are managed by the Spring IoC container
are referred to as beans. A bean is simply an
object that is instantiated, assembled and otherwise managed by a Spring
IoC container; other than that, there is nothing special about a bean (it
is in all other respects one of probably many objects in your
application). These beans, and the dependencies
between them, are reflected in the configuration
metadata used by a container.Why... bean?The motivation for using the name 'bean', as
opposed to 'component' or
'object' is rooted in the origins of the Spring
Framework itself (it arose partly as a response to the complexity of
Enterprise JavaBeans).The containerThe
org.springframework.beans.factory.BeanFactory
is the actual representation of the Spring IoC
container that is responsible for containing and
otherwise managing the aforementioned beans.The BeanFactory interface is the
central IoC container interface in Spring. Its responsibilities include
instantiating or sourcing application objects, configuring such objects,
and assembling the dependencies between these objects.There are a number of implementations of the
BeanFactory interface that come supplied
straight out-of-the-box with Spring. The most commonly used
BeanFactory implementation is the
XmlBeanFactory class. This implementation allows
you to express the objects that compose your application, and the
doubtless rich interdependencies between such objects, in terms of XML.
The XmlBeanFactory takes this XML
configuration metadata and uses it to create a
fully configured system or application.
The Spring IoC container
Configuration metadataAs can be seen in the above image, the Spring IoC container
consumes some form of configuration metadata;
this configuration metadata is nothing more than how you (as an
application developer) inform the Spring container as to how to
instantiate, configure, and assemble [the objects in
your application]. This configuration metadata is
typically supplied in a simple and intuitive XML format. When using
XML-based configuration metadata, you write bean
definitions for those beans that you want the Spring IoC
container to manage, and then let the container do its stuff.XML-based metadata is by far the most commonly used form of
configuration metadata. It is not however the
only form of configuration metadata that is allowed. The Spring IoC
container itself is totally decoupled from the
format in which this configuration metadata is actually written. The
XML-based configuration metadata format really is simple though, and
so the majority of this chapter will use the XML format to convey
key concepts and features of the Spring IoC container.You can find details of another form of metadata that the
Spring container can consume in the section entitled ResourcesThe location path or paths supplied to an
ApplicationContext constructor are
actually resource strings that allow the container to load
configuration metadata from a variety of external resources such as
the local file system, from the Java CLASSPATH,
etc.Once you have learned about Spring's IoC container, you may
wish to learn a little more about Spring's
Resource abstraction, as described in
the chapter entitled .In the vast majority of application scenarios, explicit user
code is not required to instantiate one or more instances of a Spring
IoC container. For example, in a web application scenario, a simple
eight (or so) lines of boilerplate J2EE web descriptor XML in the
web.xml file of the application will typically
suffice (see ).Spring configuration consists of at least one bean definition
that the container must manage, but typically there will be more than
one bean definition. When using XML-based configuration metadata,
these beans are configured as <bean/>
elements inside a top-level <beans/>
element.These bean definitions correspond to the actual objects that
make up your application. Typically you will have bean definitions for
your service layer objects, your data access objects (DAOs),
presentation objects such as Struts
Action instances, infrastructure
objects such as Hibernate
SessionFactories, JMS
Queues, and so forth. Typically one
does not configure fine-grained domain objects in the container,
because it is usually the responsibility of DAOs and business logic to
create/load domain objects.Find below an example of the basic structure of XML-based
configuration metadata.]]>Instantiating a containerInstantiating a Spring IoC container is straightforward.ApplicationContext context = new ClassPathXmlApplicationContext(
new String[] {"services.xml", "daos.xml"});
// an ApplicationContext is also a BeanFactory (via inheritance)
BeanFactory factory = context;Composing XML-based configuration metadataIt can often be useful to split up container definitions into
multiple XML files. One way to then load an application context which
is configured from all these XML fragments is to use the application
context constructor which takes multiple
Resource locations. With a bean
factory, a bean definition reader can be used multiple times to read
definitions from each file in turn.Generally, the Spring team prefers the above approach, since it
keeps container configuration files unaware of the fact that they are
being combined with others. An alternate approach is to use one or
more occurrences of the <import/> element to
load bean definitions from another file (or files). Let's look at a
sample:
]]>In this example, external bean definitions are being loaded from
3 files, services.xml,
messageSource.xml, and
themeSource.xml. All location paths are considered
relative to the definition file doing the importing, so
services.xml in this case must be in the same
directory or classpath location as the file doing the importing, while
messageSource.xml and
themeSource.xml must be in a
resources location below the location of the
importing file. As you can see, a leading slash is actually ignored,
but given that these are considered relative paths, it is probably
better form not to use the slash at all. The contents of the files
being imported must be valid XML bean definition files according to
the Spring Schema or DTD, including the top level
<beans/> element.It is possible to reference files in parent directories using
a relative "../" path. However, this is not recommended because it
creates a dependency on a file that is outside the current
application. This is in particular not recommended for "classpath:"
URLs (e.g. "classpath:../services.xml") where the runtime resolution
process will pick the "nearest" classpath root and then look into
its parent directory. This is fragile since classpath configuration
changes may lead to a different directory being picked.Note that you can always use fully qualified resource
locations instead of relative paths: e.g.
"file:C:/config/services.xml" or "classpath:/config/services.xml".
However, be aware that you are coupling your application's
configuration to specific absolute locations then. It is generally
preferable to keep an indirection for such absolute locations, e.g.
through "${...}" placeholders that are resolved against JVM system
properties at runtime.The beansA Spring IoC container manages one or more
beans. These beans are created using the
configuration metadata that has been supplied to the container
(typically in the form of XML <bean/>
definitions).Within the container itself, these bean definitions are
represented as BeanDefinition objects,
which contain (among other information) the following metadata:a package-qualified class name: typically
this is the actual implementation class of the bean being
defined.bean behavioral configuration elements, which state how the
bean should behave in the container (scope, lifecycle callbacks, and
so forth).references to other beans which are needed for the bean to do
its work; these references are also called
collaborators or
dependencies.other configuration settings to set in the newly created
object. An example would be the number of connections to use in a
bean that manages a connection pool, or the size limit of the
pool.The concepts listed above directly translate to a set of
properties that each bean definition consists of. Some of these
properties are listed below, along with a link to further documentation
about each of them.
Besides bean definitions which contain information on how to
create a specific bean, certain
BeanFactory implementations also permit
the registration of existing objects that have been created outside the
factory (by user code). The
DefaultListableBeanFactory class supports this
through the registerSingleton(..) method.
(Typical applications solely work with beans defined through metadata
bean definitions though.)Naming beansBean naming conventionsThe convention (at least amongst the Spring development team)
is to use the standard Java convention for instance field names when
naming beans. That is, bean names start with a lowercase letter, and
are camel-cased from then on. Examples of such names would be
(without quotes) 'accountManager',
'accountService', 'userDao',
'loginController', and so forth.Adopting a consistent way of naming your beans will go a long
way towards making your configuration easier to read and understand;
adopting such naming standards is not hard to do, and if you are
using Spring AOP it can pay off handsomely when it comes to applying
advice to a set of beans related by name.Every bean has one or more ids (also called
identifiers, or names; these terms refer to the same thing). These
ids must be unique within the container the bean is
hosted in. A bean will almost always have only one id, but if a bean
has more than one id, the extra ones can essentially be considered
aliases.When using XML-based configuration metadata, you use the
'id' or 'name' attributes to
specify the bean identifier(s). The 'id' attribute
allows you to specify exactly one id, and as it is a real XML element
ID attribute, the XML parser is able to do some extra validation when
other elements reference the id; as such, it is the preferred way to
specify a bean id. However, the XML specification does limit the
characters which are legal in XML IDs. This is usually not a
constraint, but if you have a need to use one of these special XML
characters, or want to introduce other aliases to the bean, you may
also or instead specify one or more bean ids,
separated by a comma (,), semicolon
(;), or whitespace in the 'name'
attribute.Please note that you are not required to supply a name for a
bean. If no name is supplied explicitly, the container will generate a
unique name for that bean. The motivations for not supplying a name
for a bean will be discussed later (one use case is inner beans).Aliasing beansIn a bean definition itself, you may supply more than one name
for the bean, by using a combination of up to one name specified via
the id attribute, and any number of other names
via the name attribute. All these names can be
considered equivalent aliases to the same bean, and are useful for
some situations, such as allowing each component used in an
application to refer to a common dependency using a bean name that
is specific to that component itself.Having to specify all aliases when the bean is actually
defined is not always adequate however. It is sometimes desirable to
introduce an alias for a bean which is defined elsewhere. In
XML-based configuration metadata this may be accomplished via the
use of the <alias/> element.]]>In this case, a bean in the same container which is named
'fromName', may also after the use of this alias
definition, be referred to as 'toName'.As a concrete example, consider the case where component A
defines a DataSource bean called componentA-dataSource, in its XML
fragment. Component B would however like to refer to the DataSource
as componentB-dataSource in its XML fragment. And the main
application, MyApp, defines its own XML fragment and assembles the
final application context from all three fragments, and would like
to refer to the DataSource as myApp-dataSource. This scenario can be
easily handled by adding to the MyApp XML fragment the following
standalone aliases:]]>Now each component and the main application can refer to the
dataSource via a name that is unique and guaranteed not to clash
with any other definition (effectively there is a namespace), yet
they refer to the same bean.Instantiating beansInner class namesIf for whatever reason you want to configure a bean definition
for a static inner class, you have to use the
binary name of the inner class.For example, if you have a class called
Foo in the com.example
package, and this Foo class has a
static inner class called
Bar, the value of the
'class' attribute on a bean definition would
be...com.example.Foo$BarNotice the use of the $ character in the
name to separate the inner class name from the outer class
name.A bean definition essentially is a recipe for creating one or
more objects. The container looks at the recipe for a named bean when
asked, and uses the configuration metadata encapsulated by that bean
definition to create (or acquire) an actual object.If you are using XML-based configuration metadata, you can
specify the type (or class) of object that is to be instantiated using
the 'class' attribute of the
<bean/> element. This
'class' attribute (which internally eventually
boils down to being a Class property on a
BeanDefinition instance) is normally
mandatory (see and for the two exceptions) and
is used for one of two purposes. The class property specifies the
class of the bean to be constructed in the common case where the
container itself directly creates the bean by calling its constructor
reflectively (somewhat equivalent to Java code using the
'new' operator). In the less common case where
the container invokes a static,
factory method on a class to create the bean, the
class property specifies the actual class containing the
static factory method that is to be invoked to
create the object (the type of the object returned from the invocation
of the static factory method may be the same class
or another class entirely, it doesn't matter).Instantiation using a constructorWhen creating a bean using the constructor approach, all
normal classes are usable by and compatible with Spring. That is,
the class being created does not need to implement any specific
interfaces or be coded in a specific fashion. Just specifying the
bean class should be enough. However, depending on what type of IoC
you are going to use for that specific bean, you may need a default
(empty) constructor.Additionally, the Spring IoC container isn't limited to just
managing true JavaBeans, it is also able to manage virtually
any class you want it to manage. Most people
using Spring prefer to have actual JavaBeans (having just a default
(no-argument) constructor and appropriate setters and getters
modeled after the properties) in the container, but it is also
possible to have more exotic non-bean-style classes in your
container. If, for example, you need to use a legacy connection pool
that absolutely does not adhere to the JavaBean specification,
Spring can manage it as well.When using XML-based configuration metadata you can specify
your bean class like so:]]>The mechanism for supplying arguments to the constructor (if
required), or setting properties of the object instance after it has
been constructed, is
described shortly.Instantiation using a static factory methodWhen defining a bean which is to be created using a static
factory method, along with the class attribute
which specifies the class containing the static
factory method, another attribute named
factory-method is needed to specify the name of
the factory method itself. Spring expects to be able to call this
method (with an optional list of arguments as described later) and
get back a live object, which from that point on is treated as if it
had been created normally via a constructor. One use for such a bean
definition is to call static factories in legacy
code.The following example shows a bean definition which specifies
that the bean is to be created by calling a factory-method. Note
that the definition does not specify the type (class) of the
returned object, only the class containing the factory method. In
this example, the createInstance() method
must be a static method.]]>The mechanism for supplying (optional) arguments to the
factory method, or setting properties of the object instance after
it has been returned from the factory, will be described
shortly.Instantiation using an instance factory methodIn a fashion similar to instantiation via a static factory
method, instantiation using an instance factory method is
where a non-static method of an existing bean from the container is
invoked to create a new bean. To use this mechanism, the
'class' attribute must be left empty, and the
'factory-bean' attribute must specify the name of
a bean in the current (or parent/ancestor) container that contains
the instance method that is to be invoked to create the object. The
name of the factory method itself must be set using the
'factory-method' attribute.<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="com.foo.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="exampleBean"
factory-bean="serviceLocator"
factory-method="createInstance"/>Although the mechanisms for setting bean
properties are still to be discussed, one implication of this
approach is that the factory bean itself can be managed and
configured via DI.When the Spring documentation makes mention of a 'factory
bean', this will be a reference to a bean that is configured in
the Spring container that will create objects via an instance
or static
factory method. When the documentation mentions a
FactoryBean (notice the
capitalization) this is a reference to a Spring-specific
FactoryBean .Using the containerA BeanFactory is essentially
nothing more than the interface for an advanced factory capable of
maintaining a registry of different beans and their dependencies. The
BeanFactory enables you to read bean
definitions and access them using the bean factory. When using just the
BeanFactory you would create one and read
in some bean definitions in the XML format as follows:Basically that is all there is to it. Using
getBean(String) you can retrieve instances of
your beans; the client-side view of the
BeanFactory is simple. The
BeanFactory interface has just a few
other methods, but ideally your application code should never use
them... indeed, your application code should have no calls to the
getBean(String) method at all, and thus no
dependency on Spring APIs at all.DependenciesYour typical enterprise application is not made up of a single
object (or bean in the Spring parlance). Even the simplest of applications
will no doubt have at least a handful of objects that work together to
present what the end-user sees as a coherent application. This next
section explains how you go from defining a number of bean definitions
that stand-alone, each to themselves, to a fully realized application
where objects work (or collaborate) together to achieve some goal (usually
an application that does what the end-user wants).Injecting dependenciesThe basic principle behind Dependency
Injection (DI) is that objects define their dependencies
(that is to say the other objects they work with) only through
constructor arguments, arguments to a factory method, or properties
which are set on the object instance after it has been constructed or
returned from a factory method. Then, it is the job of the container to
actually inject those dependencies when it creates
the bean. This is fundamentally the inverse, hence the name
Inversion of Control (IoC), of the bean itself
being in control of instantiating or locating its dependencies on its
own using direct construction of classes, or something like the
Service Locator pattern.It becomes evident upon usage that code gets much cleaner when the
DI principle is applied, and reaching a higher grade of decoupling is
much easier when objects do not look up their dependencies, but are
provided with them (and additionally do not even know where the
dependencies are located and of what concrete class they are). DI exists
in two major variants, namely Constructor Injection and
Setter Injection.Constructor InjectionConstructor-based DI is effected by
invoking a constructor with a number of arguments, each representing a
dependency. Additionally, calling a static factory
method with specific arguments to construct the bean, can be
considered almost equivalent, and the rest of this text will consider
arguments to a constructor and arguments to a
static factory method similarly. Find below an
example of a class that could only be dependency injected using
constructor injection. Notice that there is nothing
special about this class.public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on a MovieFinder
private MovieFinder movieFinder;
// a constructor so that the Spring container can 'inject' a MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually 'uses' the injected MovieFinder is omitted...
}Constructor Argument ResolutionConstructor argument resolution matching occurs using the
argument's type. If there is no potential for ambiguity in the
constructor arguments of a bean definition, then the order in which
the constructor arguments are defined in a bean definition is the
order in which those arguments will be supplied to the appropriate
constructor when it is being instantiated. Consider the following
class:package x.y;
public class Foo {
public Foo(Bar bar, Baz baz) {
// ...
}
}There is no potential for ambiguity here (assuming of course
that Bar and Baz
classes are not related in an inheritance hierarchy). Thus the
following configuration will work just fine, and you do not need to
specify the constructor argument indexes and / or types
explicitly.
]]>When another bean is referenced, the type is known, and
matching can occur (as was the case with the preceding example).
When a simple type is used, such as
<value>true<value>, Spring cannot
determine the type of the value, and so cannot match by type without
help. Consider the following class:package examples;
public class ExampleBean {
// No. of years to the calculate the Ultimate Answer
private int years;
// The Answer to Life, the Universe, and Everything
private String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}Constructor Argument Type MatchingThe above scenario can use type
matching with simple types by explicitly specifying the type of
the constructor argument using the 'type'
attribute. For example:
]]>Constructor Argument IndexConstructor arguments can have their index specified
explicitly by use of the index attribute. For
example:
]]>As well as solving the ambiguity problem of multiple simple
values, specifying an index also solves the problem of ambiguity
where a constructor may have two arguments of the same type. Note
that the index is 0 based.Setter InjectionSetter-based DI is realized by calling
setter methods on your beans after invoking a no-argument constructor
or no-argument static factory method to instantiate
your bean.Find below an example of a class that can only be dependency
injected using pure setter injection. Note that there is nothing
special about this class... it is plain old
Java.public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a setter method so that the Spring container can 'inject' a MovieFinder
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually 'uses' the injected MovieFinder is omitted...
}Constructor- or Setter-based DI?The Spring team generally advocates the usage of setter
injection, since a large number of constructor arguments can get
unwieldy, especially when some properties are optional. The presence
of setter methods also makes objects of that class amenable to being
re-configured (or re-injected) at some later time (for management
via JMX MBeans is a particularly
compelling use case).Constructor-injection is favored by some purists though (and
with good reason). Supplying all of an object's dependencies means
that that object is never returned to client (calling) code in a
less than totally initialized state. The flip side is that the
object becomes less amenable to re-configuration (or
re-injection).There is no hard and fast rule here. Use whatever type of DI
makes the most sense for a particular class; sometimes, when dealing
with third party classes to which you do not have the source, the
choice will already have been made for you - a legacy class may not
expose any setter methods, and so constructor injection will be the
only type of DI available to you.The BeanFactory supports both of
these variants for injecting dependencies into beans it manages. (It
in fact also supports injecting setter-based dependencies after some
dependencies have already been supplied via the constructor approach.)
The configuration for the dependencies comes in the form of a
BeanDefinition, which is used together
with PropertyEditor instances to know
how to convert properties from one format to another. However, most
users of Spring will not be dealing with these classes directly (that
is programmatically), but rather with an XML definition file which
will be converted internally into instances of these classes, and used
to load an entire Spring IoC container instance.Bean dependency resolution generally happens as follows:The BeanFactory is created
and initialized with a configuration which describes all the
beans. (Most Spring users use a
BeanFactory or
ApplicationContext implementation
that supports XML format configuration files.)Each bean has dependencies expressed in the form of
properties, constructor arguments, or arguments to the
static-factory method when that is used instead of a normal
constructor. These dependencies will be provided to the bean,
when the bean is actually created.Each property or constructor argument is either an actual
definition of the value to set, or a reference to another bean in
the container.
Each property or constructor argument which is a value must be
able to be converted from whatever format it was specified in, to
the actual type of that property or constructor argument. By
default Spring can convert a value supplied in string format to
all built-in types, such as int,
long, String,
boolean, etc.The Spring container validates the configuration of each bean as
the container is created, including the validation that properties
which are bean references are actually referring to valid beans.
However, the bean properties themselves are not set until the bean
is actually created. For those beans that are
singleton-scoped and set to be pre-instantiated (such as singleton
beans in an ApplicationContext),
creation happens at the time that the container is created, but
otherwise this is only when the bean is requested. When a bean
actually has to be created, this will potentially cause a graph of
other beans to be created, as its dependencies and its dependencies'
dependencies (and so on) are created and assigned.Circular dependenciesIf you are using predominantly constructor injection it is
possible to write and configure your classes and beans such that an
unresolvable circular dependency scenario is created.Consider the scenario where you have class A, which requires
an instance of class B to be provided via constructor injection, and
class B, which requires an instance of class A to be provided via
constructor injection. If you configure beans for classes A and B to
be injected into each other, the Spring IoC container will detect
this circular reference at runtime, and throw a
BeanCurrentlyInCreationException.One possible solution to this issue is to edit the source code
of some of your classes to be configured via setters instead of via
constructors. Another solution is not to use constructor injection
and stick to setter injection only. In other words, while it should
generally be avoided in all but the rarest of circumstances, it is
possible to configure circular dependencies with setter
injection.Unlike the typical case (with no circular
dependencies), a circular dependency between bean A and bean B will
force one of the beans to be injected into the other prior to being
fully initialized itself (a classic chicken/egg scenario).You can generally trust Spring to do the right thing. It will
detect misconfiguration issues, such as references to non-existent
beans and circular dependencies, at container load-time. It will
actually set properties and resolve dependencies as late as possible,
which is when the bean is actually created. This means that a Spring
container which has loaded correctly can later generate an exception
when you request a bean if there is a problem creating that bean or
one of its dependencies. This could happen if the bean throws an
exception as a result of a missing or invalid property, for example.
This potentially delayed visibility of some configuration issues is
why ApplicationContext implementations
by default pre-instantiate singleton beans. At the cost of some
upfront time and memory to create these beans before they are actually
needed, you find out about configuration issues when the
ApplicationContext is created, not
later. If you wish, you can still override this default behavior and
set any of these singleton beans to lazy-initialize (that is not be
pre-instantiated).If no circular dependencies are involved (see sidebar for a
discussion of circular dependencies), when one or more collaborating
beans are being injected into a dependent bean, each collaborating
bean is totally configured prior to being passed
(via one of the DI flavors) to the dependent bean. This means that if
bean A has a dependency on bean B, the Spring IoC container will
totally configure bean B prior to invoking the
setter method on bean A; you can read 'totally
configure' to mean that the bean will be instantiated (if
not a pre-instantiated singleton), all of its dependencies will be
set, and the relevant lifecycle methods (such as a configured init
method or the IntializingBean
callback method) will all be invoked.Some examplesFirst, an example of using XML-based configuration metadata for
setter-based DI. Find below a small part of a Spring XML configuration
file specifying some bean definitions.<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested <ref/> element -->
<property name="beanOne"><ref bean="anotherExampleBean"/></property>
<!-- setter injection using the neater 'ref' attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>As you can see, setters have been declared to match against the
properties specified in the XML file. Find below an example of using
constructor-based DI.<bean id="exampleBean" class="examples.ExampleBean">
<!-- constructor injection using the nested <ref/> element -->
<constructor-arg>
<ref bean="anotherExampleBean"/>
</constructor-arg>
<!-- constructor injection using the neater 'ref' attribute -->
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg type="int" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>As you can see, the constructor arguments specified in the bean
definition will be used to pass in as arguments to the constructor of
the ExampleBean.Now consider a variant of this where instead of using a
constructor, Spring is told to call a static
factory method to return an instance of the object:]]>public class ExampleBean {
// a private constructor
private ExampleBean(...) {
...
}
// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
public static ExampleBean createInstance (
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
ExampleBean eb = new ExampleBean (...);
// some other operations...
return eb;
}
}Note that arguments to the static factory
method are supplied via <constructor-arg/>
elements, exactly the same as if a constructor had actually been used.
Also, it is important to realize that the type of the class being
returned by the factory method does not have to be of the same type as
the class which contains the static factory method,
although in this example it is. An instance (non-static) factory
method would be used in an essentially identical fashion (aside from
the use of the factory-bean attribute instead of
the class attribute), so details will not be
discussed here.Dependencies and configuration in detailAs mentioned in the previous section, bean properties and
constructor arguments can be defined as either references to other
managed beans (collaborators), or values defined inline. Spring's
XML-based configuration metadata supports a number of sub-element types
within its <property/> and
<constructor-arg/> elements for just this
purpose.Straight values (primitives, Strings,
etc.)The <value/> element specifies a
property or constructor argument as a human-readable string
representation. As mentioned
previously, JavaBeans PropertyEditors are
used to convert these string values from a
String to the actual type of the property or
argument.<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/mydb</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>masterkaoli</value>
</property>
</bean>The <property/> and
<constructor-arg/> elements also support the
use of the 'value' attribute, which can lead to
much more succinct configuration. When using the
'value' attribute, the above bean definition reads
like so:<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="masterkaoli"/>
</bean>The Spring team generally prefer the attribute style over the
use of nested <value/> elements. If you are
reading this reference manual straight through from top to bottom
(wow!) then we are getting slightly ahead of ourselves here, but you
can also configure a java.util.Properties
instance like so:<bean id="mappings" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<!-- typed as a java.util.Properties -->
<property name="properties">
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
</property>
</bean>Can you see what is happening? The Spring container is
converting the text inside the <value/>
element into a java.util.Properties instance
using the JavaBeans PropertyEditor
mechanism. This is a nice shortcut, and is one of a few places where
the Spring team do favor the use of the nested
<value/> element over the
'value' attribute style.The idref elementThe idref element is simply an error-proof
way to pass the id of another bean in the
container (to a <constructor-arg/> or
<property/> element).]]>The above bean definition snippet is
exactly equivalent (at runtime) to the
following snippet:]]>The main reason the first form is preferable to the second is
that using the idref tag allows the container to
validate at deployment time that the
referenced, named bean actually exists. In the second variation, no
validation is performed on the value that is passed to the
'targetName' property of the
'client' bean. Any typo will only be discovered
(with most likely fatal results) when the
'client' bean is actually instantiated. If the
'client' bean is a prototype bean, this typo (and
the resulting exception) may only be discovered long after the
container is actually deployed.Additionally, if the bean being referred to is in the same XML
unit, and the bean name is the bean id, the
'local' attribute may be used, which allows the
XML parser itself to validate the bean id even earlier, at XML
document parse time.<property name="targetName">
<!-- a bean with an id of 'theTargetBean' must exist; otherwise an XML exception will be thrown -->
<idref local="theTargetBean"/>
</property>By way of an example, one common place (at least in pre-Spring
2.0 configuration) where the <idref/> element brings value is
in the configuration of AOP
interceptors in a ProxyFactoryBean
bean definition. If you use <idref/> elements when specifying
the interceptor names, there is no chance of inadvertently
misspelling an interceptor id.References to other beans (collaborators)The ref element is the final element allowed
inside a <constructor-arg/> or
<property/> definition element. It is used to
set the value of the specified property to be a reference to another
bean managed by the container (a collaborator). As mentioned in a
previous section, the referred-to bean is considered to be a
dependency of the bean who's property is being set, and will be
initialized on demand as needed (if it is a singleton bean it may have
already been initialized by the container) before the property is set.
All references are ultimately just a reference to another object, but
there are 3 variations on how the id/name of the other object may be
specified, which determines how scoping and validation is
handled.Specifying the target bean by using the bean
attribute of the <ref/> tag is the most
general form, and will allow creating a reference to any bean in the
same container (whether or not in the same XML file), or parent
container. The value of the 'bean' attribute may be
the same as either the 'id' attribute of the target
bean, or one of the values in the 'name' attribute
of the target bean.]]>Specifying the target bean by using the local
attribute leverages the ability of the XML parser to validate XML id
references within the same file. The value of the
local attribute must be the same as the
id attribute of the target bean. The XML parser
will issue an error if no matching element is found in the same file.
As such, using the local variant is the best choice (in order to know
about errors as early as possible) if the target bean is in the same
XML file.]]>Specifying the target bean by using the
'parent' attribute allows a reference to be created
to a bean which is in a parent container of the current container. The
value of the 'parent' attribute may be the same as
either the 'id' attribute of the target bean, or
one of the values in the 'name' attribute of the
target bean, and the target bean must be in a parent container to the
current one. The main use of this bean reference variant is when you
have a hierarchy of containers and you want to wrap an existing bean
in a parent container with some sort of proxy which will have the same
name as the parent bean.<!-- in the parent context -->
<bean id="accountService" class="com.foo.SimpleAccountService">
<!-- insert dependencies as required as here -->
</bean><!-- in the child (descendant) context -->
<bean id="accountService" <-- notice that the name of this bean is the same as the name of the 'parent' bean
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref parent="accountService"/> <-- notice how we refer to the parent bean
</property>
<!-- insert other configuration and dependencies as required as here -->
</bean>Inner beansA <bean/> element inside the
<property/> or
<constructor-arg/> elements is used to define
a so-called inner bean. An inner bean
definition does not need to have any id or name defined, and it is
best not to even specify any id or name value because the id or name
value simply will be ignored by the container.<bean id="outer" class="...">
<!-- instead of using a reference to a target bean, simply define the target bean inline -->
<property name="target">
<bean class="com.example.Person"> <!-- this is the inner bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>Note that in the specific case of inner beans, the
'scope' flag and any 'id' or
'name' attribute are effectively ignored. Inner
beans are always anonymous and they are
always scoped as prototypes. Please
also note that it is not possible to inject inner
beans into collaborating beans other than the enclosing bean.CollectionsThe <list/>,
<set/>, <map/>, and
<props/> elements allow properties and
arguments of the Java Collection type
List,
Set,
Map, and
Properties, respectively, to be defined
and set.<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry>
<key>
<value>an entry</value>
</key>
<value>just some string</value>
</entry>
<entry>
<key>
<value>a ref</value>
</key>
<ref bean="myDataSource" />
</entry>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>The nested element style used this initial example tends to
become quite verbose. Fortunately, there are attribute shortcuts for
most elements, which you can read about in .Note that the value of a map key or value, or a set
value, can also again be any of the following
elements:Collection mergingAs of Spring 2.0, the container also supports the
merging of collections. This allows an
application developer to define a parent-style
<list/>, <map/>,
<set/> or <props/>
element, and have child-style <list/>,
<map/>, <set/> or
<props/> elements inherit and override
values from the parent collection; that is to say the child
collection's values will be the result obtained from the merging of
the elements of the parent and child collections, with the child's
collection elements overriding values specified in the parent
collection.Please note that this section on merging makes use
of the parent-child bean mechanism. This concept has not yet been
introduced, so readers unfamiliar with the concept of parent and
child bean definitions may wish to read the relevant section
before continuing.Find below an example of the collection merging
feature:<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.com</prop>
<prop key="support">support@example.com</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- the merge is specified on the *child* collection definition -->
<props merge="true">
<prop key="sales">sales@example.com</prop>
<prop key="support">support@example.co.uk</prop>
</props>
</property>
</bean>
<beans>Notice the use of the merge=true attribute
on the <props/> element of the
adminEmails property of the
child bean definition. When the
child bean is actually resolved and instantiated
by the container, the resulting instance will have an
adminEmailsProperties
collection that contains the result of the merging of the child's
adminEmails collection with the parent's
adminEmails collection.Notice how the child Properties
collection's value set will have inherited all the property elements
from the parent <props/>. Notice also how
the child's value for the support value overrides
the value in the parent collection.This merging behavior applies similarly to the
<list/>, <map/>,
and <set/> collection types. In the
specific case of the <list/> element, the
semantics associated with the List collection
type, that is the notion of an ordered collection
of values, is maintained; the parent's values will precede all of
the child list's values. In the case of the
Map,
Set, and
Properties collection types, there is
no notion of ordering and hence no ordering semantics are in effect
for the collection types that underlie the associated
Map,
Set and
Properties implementation types used
internally by the container.Finally, some minor notes about the merging support are in
order; you cannot merge different collection types (e.g. a
Map and a
List), and if you do attempt to do so
an appropriate Exception will be thrown; and
in case it is not immediately obvious, the
'merge' attribute must be specified on the lower
level, inherited, child definition; specifying the
'merge' attribute on a parent collection
definition is redundant and will not result in the desired merging;
and (lastly), please note that this merging feature is only
available in Spring 2.0 (and later versions).Strongly-typed collection (Java 5+ only)If you are using Java 5 or Java 6, you will be aware that it
is possible to have strongly typed collections (using generic
types). That is, it is possible to declare a
Collection type such that it can only
contain String elements (for example). If you
are using Spring to dependency inject a strongly-typed
Collection into a bean, you can take
advantage of Spring's type-conversion support such that the elements
of your strongly-typed Collection
instances will be converted to the appropriate type prior to being
added to the Collection. accounts;
public void setAccounts(Map accounts) {
this.accounts = accounts;
}
}]]>
]]>When the 'accounts' property of the
'foo' bean is being prepared for injection, the
generics information about the element type of the strongly-typed
Map<String, Float> is actually
available via reflection, and so Spring's type conversion
infrastructure will actually recognize the various value elements as
being of type Float and so the string values
'9.99', '2.75', and '3.99'
will be converted into an actual Float
type.NullsThe <null/> element is used to handle
null values. Spring treats empty arguments for
properties and the like as empty Strings. The
following XML-based configuration metadata snippet results in the
email property being set to the empty String
value ("")
]]>This is equivalent to the following Java code:
exampleBean.setEmail(""). The special
<null> element may be used to indicate a
null value. For example:
]]>The above configuration is equivalent to the following Java
code: exampleBean.setEmail(null).Shortcuts and other convenience options for XML-based
configuration metadataThe configuration metadata shown so far is a tad verbose. That
is why there are several options available for you to limit the amount
of XML you have to write to configure your components. The first is a
shortcut to define values and references to other beans as part of a
<property/> definition. The second is
slightly different format of specifying properties altogether.XML-based configuration metadata shortcutsThe <property/>,
<constructor-arg/>, and
<entry/> elements all support a
'value' attribute which may be used instead of
embedding a full <value/> element.
Therefore, the following:hello
]]>hello
]]>hello
]]>are equivalent to:]]>]]>]]>The <property/> and
<constructor-arg/> elements support a
similar shortcut 'ref' attribute which may be
used instead of a full nested <ref/>
element. Therefore, the following:
]]>
]]>... are equivalent to:]]>]]>Note however that the shortcut form is equivalent to a
<ref bean="xxx"> element; there is no
shortcut for <ref local="xxx">. To enforce
a strict local reference, you must use the long form.Finally, the entry element allows a shortcut form to specify
the key and/or value of the map, in the form of the
'key' / 'key-ref' and
'value' / 'value-ref'
attributes. Therefore, the following:
]]>is equivalent to:]]>Again, the shortcut form is equivalent to a <ref
bean="xxx"> element; there is no shortcut for
<ref local="xxx">.The p-namespace and how to use it to configure
propertiesThe second option you have to limit the amount of XML you have
to write to configure your components is to use the special
"p-namespace". Spring 2.0 and later features support for extensible
configuration formats using
namespaces. Those namespaces are all based on an XML Schema
definition. In fact, the beans configuration
format that you've been reading about is defined in an XML Schema
document.One special namespace is not defined in an XSD file, and only
exists in the core of Spring itself. The so-called p-namespace
doesn't need a schema definition and is an alternative way of
configuring your properties differently than the way you have seen
so far. Instead of using nested <property/>
elements, using the p-namespace you can use attributes as part of
the bean element that describe your property
values. The values of the attributes will be taken as the values for
your properties.The following two XML snippets boil down to the same thing in
the end: the first is using the standard XML format whereas the
second example is using the p-namespace.
]]>As you can see, we are including an attribute in the
p-namespace called email in the bean definition - this is telling
Spring that it should include a property declaration. As previously
mentioned, the p-namespace doesn't have a schema definition, so the
name of the attribute can be set to whatever name your property
has.This next example includes two more bean definitions that both
have a reference to another bean:
]]>As you can see, this example doesn't only include a property
value using the p-namespace, but also uses a special format to
declare property references. Whereas the first bean definition uses
<property name="spouse" ref="jane"/> to
create a reference from bean john to bean
jane, the second bean definition uses
p:spouse-ref="jane" as an attribute to do the
exact same thing. In this case 'spouse' is the
property name whereas the '-ref' part indicates
that this is not a straight value but rather a reference to another
bean.Please note that the p-namespace is not quite as flexible as
the standard XML format - for example particular, the 'special'
format used to declare property references will clash with
properties that end in 'Ref', whereas the
standard XML format would have no problem there. We recommend that
you choose carefully which approach you are going to use in your
projects. You should also communicate this to your team members so
you won't end up with XML documents using all three approaches at
the same time. This will prevent people from not understanding the
application because of different ways of configuring it, and will
add to the overall consistency of your codebase.Compound property namesCompound or nested property names are perfectly legal when
setting bean properties, as long as all components of the path except
the final property name are not null. Consider the
following bean definition...
]]>The foo bean has a fred
property which has a bob property, which has a
sammy property, and that final
sammy property is being set to the value
123. In order for this to work, the
fred property of foo, and the
bob property of fred must not be
null be non-null after the bean is constructed, or
a NullPointerException will be
thrown.Using depends-onFor most situations, the fact that a bean is a dependency of
another is expressed by the fact that one bean is set as a property of
another. This is typically accomplished with the <ref/>
element in XML-based configuration metadata. For the relatively
infrequent situations where dependencies between beans are less direct
(for example, when a static initializer in a class needs to be
triggered, such as database driver registration), the
'depends-on' attribute may be used to explicitly
force one or more beans to be initialized before the bean using this
element is initialized. Find below an example of using the
'depends-on' attribute to express a dependency on a
single bean.<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />If you need to express a dependency on multiple beans, you can
supply a list of bean names as the value of the
'depends-on' attribute, with commas, whitespace and
semicolons all valid delimiters, like so:]]>The 'depends-on' attribute at the bean
definition level is used not only to specify an initialization time
dependency, but also to specify the corresponding destroy time
dependency (in the case of singleton beans only).
Dependent beans that define a 'depends-on'
relationship with a given bean will be destroyed first - prior to the
given bean itself being destroyed. As a consequence,
'depends-on' may be used to control shutdown order
too.Lazily-instantiated beansThe default behavior for
ApplicationContext implementations is to
eagerly pre-instantiate all singleton beans at
startup. Pre-instantiation means that an
ApplicationContext will eagerly create
and configure all of its singleton beans as part
of its initialization process. Generally this is a good
thing, because it means that any errors in the configuration
or in the surrounding environment will be discovered immediately (as
opposed to possibly hours or even days down the line).However, there are times when this behavior is
not what is wanted. If you do not want a singleton
bean to be pre-instantiated when using an
ApplicationContext, you can selectively
control this by marking a bean definition as lazy-initialized. A
lazily-initialized bean indicates to the IoC container whether or not a
bean instance should be created at startup or when it is first
requested.When configuring beans via XML, this lazy loading is controlled by
the 'lazy-init' attribute on the
<bean/> element; for example:<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.foo.AnotherBean"/>When the above configuration is consumed by an
ApplicationContext, the bean named
'lazy' will not be eagerly
pre-instantiated when the
ApplicationContext is starting up,
whereas the 'not.lazy' bean will be eagerly
pre-instantiated.One thing to understand about lazy-initialization is that even
though a bean definition may be marked up as being lazy-initialized, if
the lazy-initialized bean is the dependency of a singleton bean that is
not lazy-initialized, when the
ApplicationContext is eagerly
pre-instantiating the singleton, it will have to satisfy all of the
singletons dependencies, one of which will be the lazy-initialized bean!
So don't be confused if the IoC container creates one of the beans that
you have explicitly configured as lazy-initialized at startup; all that
means is that the lazy-initialized bean is being injected into a
non-lazy-initialized singleton bean elsewhere.It is also possible to control lazy-initialization at the
container level by using the 'default-lazy-init'
attribute on the <beans/> element; for
example:<beans default-lazy-init="true">
<!-- no beans will be pre-instantiated... -->
</beans>Autowiring collaboratorsThe Spring container is able to autowire
relationships between collaborating beans. This means that it is
possible to automatically let Spring resolve collaborators (other beans)
for your bean by inspecting the contents of the
BeanFactory. The autowiring functionality
has five modes. Autowiring is specified per bean
and can thus be enabled for some beans, while other beans will not be
autowired. Using autowiring, it is possible to reduce or eliminate the
need to specify properties or constructor arguments, thus saving a
significant amount of typing. See the section entitled When using XML-based configuration metadata, the autowire
mode for a bean definition is specified by using the
autowire attribute of the
<bean/> element. The following values are
allowed:
Autowiring modesModeExplanationnoNo autowiring at all. Bean references must be
defined via a ref element. This is the
default, and changing this is discouraged for larger
deployments, since explicitly specifying collaborators gives
greater control and clarity. To some extent, it is a form of
documentation about the structure of a system.byNameAutowiring by property name. This option will
inspect the container and look for a bean named exactly the same
as the property which needs to be autowired. For example, if you
have a bean definition which is set to autowire by name, and it
contains a master property (that is, it has
a setMaster(..) method), Spring will look
for a bean definition named master, and use
it to set the property.byTypeAllows a property to be autowired if there is
exactly one bean of the property type in the container. If there
is more than one, a fatal exception is thrown, and this
indicates that you may not use byType
autowiring for that bean. If there are no matching beans,
nothing happens; the property is not set. If this is not
desirable, setting the
dependency-check="objects" attribute value
specifies that an error should be thrown in this
case.constructorThis is analogous to byType,
but applies to constructor arguments. If there isn't exactly one
bean of the constructor argument type in the container, a fatal
error is raised.autodetectChooses constructor or
byType through introspection of the bean
class. If a default constructor is found, the
byType mode will be applied.
Note that explicit dependencies in property and
constructor-arg settings
always override autowiring. Please also
note that it is not currently possible to autowire so-called
simple properties such as primitives,
Strings, and Classes (and
arrays of such simple properties). (This is by-design and should be
considered a feature.) When using either the
byType or constructor
autowiring mode, it is possible to wire arrays and typed-collections. In
such cases all autowire candidates within the
container that match the expected type will be provided to satisfy the
dependency. Strongly-typed Maps can even be autowired if the expected
key type is String. An autowired Map's values
will consist of all bean instances that match the expected type, and the
Map's keys will contain the corresponding bean names.Autowire behavior can be combined with dependency checking, which
will be performed after all autowiring has been completed.It is important to understand the various advantages and
disadvantages of autowiring. Some advantages of autowiring
include:Autowiring can significantly reduce the volume of
configuration required. However, mechanisms such as the use of a
bean template (discussed elsewhere in this
chapter) are also valuable in this regard.Autowiring can cause configuration to keep itself up to date
as your objects evolve. For example, if you need to add an
additional dependency to a class, that dependency can be satisfied
automatically without the need to modify configuration. Thus there
may be a strong case for autowiring during development, without
ruling out the option of switching to explicit wiring when the code
base becomes more stable.Some disadvantages of autowiring:Autowiring is more magical than explicit wiring. Although, as
noted in the above table, Spring is careful to avoid guessing in
case of ambiguity which might have unexpected results, the
relationships between your Spring-managed objects are no longer
documented explicitly.Wiring information may not be available to tools that may
generate documentation from a Spring container.Another issue to consider when autowiring by type is that multiple
bean definitions within the container may match the type specified by
the setter method or constructor argument to be autowired. For arrays,
collections, or Maps, this is not necessarily a problem. However for
dependencies that expect a single value, this ambiguity will not be
arbitrarily resolved. Instead, if no unique bean definition is
available, an Exception will be thrown. You do have several options when
confronted with this scenario. First, you may abandon autowiring in
favor of explicit wiring. Second, you may designate that certain bean
definitions are never to be considered as candidates by setting their
'autowire-candidate' attributes to
'false' as described in the next section. Third, you
may designate a single bean definition as the
primary candidate by setting the
'primary' attribute of its
<bean/> element to 'true'.
Finally, if you are using at least Java 5, you may be interested in
exploring the more fine-grained control available with annotation-based
configuration as described in the section entitled .When deciding whether to use autowiring, there is no wrong or
right answer in all cases. A degree of consistency across a project is
best though; for example, if autowiring is not used in general, it might
be confusing to developers to use it just to wire one or two bean
definitions.Excluding a bean from being available for autowiringYou can also (on a per-bean basis) totally exclude a bean from
being an autowire candidate. When configuring beans using Spring's XML
format, the 'autowire-candidate' attribute of the
<bean/> element can be set to
'false'; this has the effect of making the
container totally exclude that specific bean definition from being
available to the autowiring infrastructure.Another option is to limit autowire candidates based on
pattern-matching against bean names. The top-level
<beans/> element accepts one or more patterns
within its 'default-autowire-candidates' attribute.
For example, to limit autowire candidate status to any bean whose name
ends with 'Repository', provide a value of
'*Repository'. To provide multiple patterns, define them in a
comma-separated list. Note that an explicit value of
'true' or 'false' for a bean
definition's 'autowire-candidate' attribute always
takes precedence, and for such beans, the pattern matching rules will
not apply.These techniques can be useful when you have one or more beans
that you absolutely never ever want to have injected into other beans
via autowiring. It does not mean that an excluded bean cannot itself
be configured using autowiring... it can, it is rather that it itself
will not be considered as a candidate for autowiring other
beans.Checking for dependenciesThe Spring IoC container also has the ability to check for the
existence of unresolved dependencies of a bean deployed into the
container. These are JavaBeans properties of the bean, which do not have
actual values set for them in the bean definition, or alternately
provided automatically by the autowiring feature.This feature is sometimes useful when you want to ensure that all
properties (or all properties of a certain type) are set on a bean. Of
course, in many cases a bean class will have default values for many
properties, or some properties do not apply to all usage scenarios, so
this feature is of limited use. Dependency checking can also be enabled
and disabled per bean, just as with the autowiring functionality. The
default is to not check dependencies. Dependency
checking can be handled in several different modes. When using XML-based
configuration metadata, this is specified via the
'dependency-check' attribute in a bean definition,
which may have the following values.
Dependency checking modesModeExplanationnoneNo dependency checking. Properties of the bean
which have no value specified for them are simply not
set.simpleDependency checking is performed for primitive
types and collections (everything except
collaborators).objectDependency checking is performed for collaborators
only.allDependency checking is done for collaborators,
primitive types and collections.
If you are using Java 5 and thus have access to source-level
annotations, you may find the section entitled to be of interest.Method InjectionFor most application scenarios, the majority of the beans in the
container will be singletons. When a
singleton bean needs to collaborate with another singleton bean, or a
non-singleton bean needs to collaborate with another non-singleton bean,
the typical and common approach of handling this dependency by defining
one bean to be a property of the other is quite adequate. There is a
problem when the bean lifecycles are different. Consider a singleton
bean A which needs to use a non-singleton (prototype) bean B, perhaps on
each method invocation on A. The container will only create the
singleton bean A once, and thus only get the opportunity to set the
properties once. There is no opportunity for the container to provide
bean A with a new instance of bean B every time one is needed.One solution to this issue is to forego some inversion of control.
Bean A can be made
aware of the container by implementing the
BeanFactoryAware interface, and use programmatic means to ask the
container via a getBean("B") call for (a
typically new) bean B instance every time it needs it. Find below an
admittedly somewhat contrived example of this approach:// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// lots of Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
public class CommandManager implements BeanFactoryAware {
private BeanFactory beanFactory;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
// the Command returned here could be an implementation that executes asynchronously, or whatever
protected Command createCommand() {
return (Command) this.beanFactory.getBean("command"); // notice the Spring API dependency
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}The above example is generally not a desirable solution since the
business code is then aware of and coupled to the Spring Framework.
Method Injection, a somewhat advanced feature of the Spring IoC
container, allows this use case to be handled in a clean fashion.Lookup method injectionIsn't this Method Injection...... somewhat like Tapestry 4.0's pages, where folks wrote
abstract properties that Tapestry would override
at runtime with implementations that did stuff? It sure is (well,
somewhat).You can read more about the motivation for Method Injection in
this blog
entry.Lookup method injection refers to the ability of the container
to override methods on container managed beans,
to return the result of looking up another named bean in the
container. The lookup will typically be of a prototype bean as in the
scenario described above. The Spring Framework implements this method
injection by dynamically generating a subclass overriding the method,
using bytecode generation via the CGLIB library.So if you look at the code from previous code snippet (the
CommandManager class), the Spring container is
going to dynamically override the implementation of the
createCommand() method. Your
CommandManager class is not going to have any
Spring dependencies, as can be seen in this reworked example
below:package fiona.apple;
// no more Spring imports!
public abstract class CommandManager {
public Object process(Object commandState) {
// grab a new instance of the appropriate Command interface
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
// okay... but where is the implementation of this method?
protected abstract Command createCommand();
}In the client class containing the method to be injected (the
CommandManager in this case), the method that
is to be 'injected' must have a signature of the following
form:<public|protected> [abstract] <return-type> theMethodName(no-arguments);If the method is abstract, the
dynamically-generated subclass will implement the method. Otherwise,
the dynamically-generated subclass will override the concrete method
defined in the original class. Let's look at an example:<!-- a stateful bean deployed as a prototype (non-singleton) -->
<bean id="command" class="fiona.apple.AsyncCommand" scope="prototype">
<!-- inject dependencies here as required -->
</bean>
<!-- commandProcessor uses statefulCommandHelper -->
<bean id="commandManager" class="fiona.apple.CommandManager">
<lookup-method name="createCommand" bean="command"/>
</bean>The bean identified as commandManager will
call its own method createCommand() whenever
it needs a new instance of the command bean. It
is important to note that the person deploying the beans must be
careful to deploy the command bean as a prototype
(if that is actually what is needed). If it is deployed as a singleton, the same
instance of the command bean will be returned each
time!Please be aware that in order for this dynamic subclassing to
work, you will need to have the CGLIB jar(s) on your classpath.
Additionally, the class that the Spring container is going to subclass
cannot be final, and the method that is being
overridden cannot be final either. Also, testing a
class that has an abstract method can be somewhat
odd in that you will have to subclass the class yourself and supply a
stub implementation of the abstract method.
Finally, objects that have been the target of method injection cannot
be serialized.The interested reader may also find the
ServiceLocatorFactoryBean (in the
org.springframework.beans.factory.config package)
to be of use; the approach is similar to that of the
ObjectFactoryCreatingFactoryBean, but it
allows you to specify your own lookup interface as opposed to having
to use a Spring-specific lookup interface such as the
ObjectFactory. Consult the (copious)
Javadoc for the ServiceLocatorFactoryBean for
a full treatment of this alternative approach (that
does reduce the coupling to Spring).Arbitrary method replacementA less commonly useful form of method injection than Lookup
Method Injection is the ability to replace arbitrary methods in a
managed bean with another method implementation. Users may safely skip
the rest of this section (which describes this somewhat advanced
feature), until this functionality is actually needed.When using XML-based configuration metadata, the
replaced-method element may be used to replace an
existing method implementation with another, for a deployed bean.
Consider the following class, with a method computeValue, which we
want to override:public class MyValueCalculator {
public String computeValue(String input) {
// some real code...
}
// some other methods...
}A class implementing the
org.springframework.beans.factory.support.MethodReplacer
interface provides the new method definition./** meant to be used to override the existing computeValue(String)
implementation in MyValueCalculator
*/
public class ReplacementComputeValue implements MethodReplacer {
public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
// get the input value, work with it, and return a computed result
String input = (String) args[0];
...
return ...;
}
}The bean definition to deploy the original class and specify the
method override would look like this:<bean id="myValueCalculator class="x.y.z.MyValueCalculator">
<!-- arbitrary method replacement -->
<replaced-method name="computeValue" replacer="replacementComputeValue">
<arg-type>String</arg-type>
</replaced-method>
</bean>
<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>One or more contained <arg-type/>
elements within the <replaced-method/>
element may be used to indicate the method signature of the method
being overridden. Note that the signature for the arguments is
actually only needed in the case that the method is actually
overloaded and there are multiple variants within the class. For
convenience, the type string for an argument may be a substring of the
fully qualified type name. For example, all the following would match
java.lang.String.Since the number of arguments is often enough to distinguish
between each possible choice, this shortcut can save a lot of typing,
by allowing you to type just the shortest string that will match an
argument type.Bean scopesWhen you create a bean definition what you are actually creating is
a recipe for creating actual instances of the class
defined by that bean definition. The idea that a bean definition is a
recipe is important, because it means that, just like a class, you can
potentially have many object instances created from a single
recipe.You can control not only the various dependencies and configuration
values that are to be plugged into an object that is created from a
particular bean definition, but also the scope of
the objects created from a particular bean definition. This approach is
very powerful and gives you the flexibility to choose
the scope of the objects you create through configuration instead of
having to 'bake in' the scope of an object at the Java class level. Beans
can be defined to be deployed in one of a number of scopes: out of the
box, the Spring Framework supports exactly five scopes (of which three are
available only if you are using a web-aware
ApplicationContext).The scopes supported out of the box are listed below:
Bean scopesScopeDescription singleton
Scopes a single bean definition to a single object
instance per Spring IoC container. prototype
Scopes a single bean definition to any number of
object instances. request
Scopes a single bean definition to the lifecycle of a
single HTTP request; that is each and every HTTP request will have
its own instance of a bean created off the back of a single bean
definition. Only valid in the context of a web-aware Spring
ApplicationContext. session
Scopes a single bean definition to the lifecycle of a
HTTP Session. Only valid in the
context of a web-aware Spring
ApplicationContext. global
session Scopes a single bean definition to the lifecycle of a
global HTTP Session. Typically only
valid when used in a portlet context. Only valid in the context of
a web-aware Spring
ApplicationContext.
The singleton scopeWhen a bean is a singleton, only one shared
instance of the bean will be managed, and all requests for beans with an
id or ids matching that bean definition will result
in that one specific bean instance being returned by the Spring
container.To put it another way, when you define a bean definition and it is
scoped as a singleton, then the Spring IoC container will create
exactly one instance of the object defined by that
bean definition. This single instance will be stored in a cache of such
singleton beans, and all subsequent requests and
references for that named bean will result in the cached
object being returned.Please be aware that Spring's concept of a singleton bean is quite
different from the Singleton pattern as defined in the seminal Gang of
Four (GoF) patterns book. The GoF Singleton hard codes the scope of an
object such that one and only one instance of a
particular class will ever be created per
ClassLoader. The scope of the Spring
singleton is best described as per container and per
bean. This means that if you define one bean for a particular
class in a single Spring container, then the Spring container will
create one and only one instance of the class
defined by that bean definition. The singleton scope is the
default scope in Spring. To define a bean as a singleton in
XML, you would write configuration like so:<bean id="accountService" class="com.foo.DefaultAccountService"/>
<!-- the following is equivalent, though redundant (singleton scope is the default); using spring-beans-2.0.dtd -->
<bean id="accountService" class="com.foo.DefaultAccountService" scope="singleton"/>
<!-- the following is equivalent and preserved for backward compatibility in spring-beans.dtd -->
<bean id="accountService" class="com.foo.DefaultAccountService" singleton="true"/>The prototype scopeThe non-singleton, prototype scope of bean deployment results in
the creation of a new bean instance every time a
request for that specific bean is made (that is, it is injected into
another bean or it is requested via a programmatic
getBean() method call on the container). As a rule of
thumb, you should use the prototype scope for all beans that are
stateful, while the singleton scope should be used for stateless
beans.The following diagram illustrates the Spring prototype scope.
Please note that a DAO would not typically be configured as a
prototype, since a typical DAO would not hold any conversational state;
it was just easier for this author to reuse the core of the singleton
diagram.To define a bean as a prototype in XML, you would write
configuration like so:<!-- using spring-beans-2.0.dtd -->
<bean id="accountService" class="com.foo.DefaultAccountService" scope="prototype"/>
<!-- the following is equivalent and preserved for backward compatibility in spring-beans.dtd -->
<bean id="accountService" class="com.foo.DefaultAccountService" singleton="false"/>There is one quite important thing to be aware of when deploying a
bean in the prototype scope, in that the lifecycle of the bean changes
slightly. Spring does not manage the complete lifecycle of a prototype
bean: the container instantiates, configures, decorates and otherwise
assembles a prototype object, hands it to the client and then has no
further knowledge of that prototype instance. This means that while
initialization lifecycle callback methods will be
called on all objects regardless of scope, in the case of prototypes,
any configured destruction lifecycle callbacks will
not be called. It is the responsibility of the
client code to clean up prototype scoped objects and release any
expensive resources that the prototype bean(s) are holding onto. (One
possible way to get the Spring container to release resources used by
prototype-scoped beans is through the use of a custom bean post-processor which
would hold a reference to the beans that need to be cleaned up.)In some respects, you can think of the Spring containers role when
talking about a prototype-scoped bean as somewhat of a replacement for
the Java 'new' operator. All lifecycle aspects past
that point have to be handled by the client. (The lifecycle of a bean in
the Spring container is further described in the section entitled .)Singleton beans with prototype-bean dependenciesWhen using singleton-scoped beans that have dependencies on beans
that are scoped as prototypes, please be aware that
dependencies are resolved at instantiation time.
This means that if you dependency inject a prototype-scoped bean into a
singleton-scoped bean, a brand new prototype bean will be instantiated
and then dependency injected into the singleton bean... but
that is all. That exact same prototype instance will be the
sole instance that is ever supplied to the singleton-scoped bean, which
is fine if that is what you want.However, sometimes what you actually want is for the
singleton-scoped bean to be able to acquire a brand new instance of the
prototype-scoped bean again and again and again at runtime. In that case
it is no use just dependency injecting a prototype-scoped bean into your
singleton bean, because as explained above, that only happens
once when the Spring container is instantiating the
singleton bean and resolving and injecting its dependencies. If you are
in the scenario where you need to get a brand new instance of a
(prototype) bean again and again and again at runtime, you are referred
to the section entitled Backwards compatibility note: specifying the lifecycle scope in
XMLIf you are referencing the
'spring-beans.dtd' DTD in a bean definition
file(s), and you are being explicit about the lifecycle scope of your
beans you must use the "singleton" attribute to
express the lifecycle scope (remembering that the singleton lifecycle
scope is the default). If you are referencing the
'spring-beans-2.0.dtd' DTD or the Spring 2.0 XSD
schema, then you will need to use the "scope"
attribute (because the "singleton" attribute was
removed from the definition of the new DTD and XSD files in favor of
the "scope" attribute).To be totally clear about this, this means that if you use the
"singleton" attribute in an XML bean definition
then you must be referencing the
'spring-beans.dtd' DTD in that
file. If you are using the "scope"
attribute then you must be referencing either the
'spring-beans-2.0.dtd' DTD or the
'spring-beans-2.5.xsd' XSD in that
file.The other scopesThe other scopes, namely request,
session, and global session are
for use only in web-based applications (and can be used irrespective of
which particular web application framework you are using, if indeed
any). In the interest of keeping related concepts together in one place
in the reference documentation, these scopes are described here.The scopes that are described in the following paragraphs are
only available if you are using a web-aware
Spring ApplicationContext
implementation (such as
XmlWebApplicationContext). If you try using
these next scopes with regular Spring IoC containers such as the
XmlBeanFactory or
ClassPathXmlApplicationContext, you
will get an
IllegalStateException complaining about an
unknown bean scope.Initial web configurationIn order to support the scoping of beans at the
request, session, and
global session levels (web-scoped beans), some
minor initial configuration is required before you can set about
defining your bean definitions. Please note that this extra setup is
not required if you just want to use the
'standard' scopes (namely singleton and prototype).Now as things stand, there are a couple of ways to effect this
initial setup depending on your particular Servlet
environment...If you are accessing scoped beans within Spring Web MVC, i.e.
within a request that is processed by the Spring
DispatcherServlet, or
DispatcherPortlet, then no special setup is
necessary: DispatcherServlet and
DispatcherPortlet already expose all relevant
state.When using a Servlet 2.4+ web container, with requests processed
outside of Spring's DispatcherServlet (e.g. when using JSF or Struts),
you need to add the following
javax.servlet.ServletRequestListener to
the declarations in your web application's
'web.xml' file.
...
org.springframework.web.context.request.RequestContextListener
...
]]>If you are using an older web container (Servlet 2.3), you will
need to use the provided
javax.servlet.Filter implementation.
Find below a snippet of XML configuration that has to be included in
the 'web.xml' file of your web application if you
want to have access to web-scoped beans in requests outside of
Spring's DispatcherServlet on a Servlet 2.3 container. (The filter
mapping depends on the surrounding web application configuration and
so you will have to change it as appropriate.)
..
requestContextFilterorg.springframework.web.filter.RequestContextFilterrequestContextFilter/*
...
]]>That's it. DispatcherServlet,
RequestContextListener and
RequestContextFilter all do exactly the same
thing, namely bind the HTTP request object to the
Thread that is servicing that request. This
makes beans that are request- and session-scoped available further
down the call chain.The request scopeConsider the following bean definition:]]>With the above bean definition in place, the Spring container
will create a brand new instance of the
LoginAction bean using the
'loginAction' bean definition for each and every
HTTP request. That is, the 'loginAction' bean will
be effectively scoped at the HTTP request level. You can change or
dirty the internal state of the instance that is created as much as
you want, safe in the knowledge that other requests that are also
using instances created off the back of the same
'loginAction' bean definition will not be seeing
these changes in state since they are particular to an individual
request. When the request is finished processing, the bean that is
scoped to the request will be discarded.The session scopeConsider the following bean definition:]]>With the above bean definition in place, the Spring container
will create a brand new instance of the
UserPreferences bean using the
'userPreferences' bean definition for the lifetime
of a single HTTP Session. In other
words, the 'userPreferences' bean will be
effectively scoped at the HTTP Session
level. Just like request-scoped beans, you can
change the internal state of the instance that is created as much as
you want, safe in the knowledge that other HTTP
Session instances that are also using
instances created off the back of the same
'userPreferences' bean definition will not be
seeing these changes in state since they are particular to an
individual HTTP Session. When the HTTP
Session is eventually discarded, the
bean that is scoped to that particular HTTP
Session will also be discarded.The global session scopeConsider the following bean definition:]]>The global session scope is similar to the
standard HTTP Session scope (described immediately
above), and really only makes sense in the context of
portlet-based web applications. The portlet specification defines the
notion of a global Session that is
shared amongst all of the various portlets that make up a single
portlet web application. Beans defined at the global
session scope are scoped (or bound) to the lifetime of the
global portlet Session.Please note that if you are writing a standard Servlet-based web
application and you define one or more beans as having global
session scope, the standard HTTP
Session scope will be used, and no
error will be raised.Scoped beans as dependenciesBeing able to define a bean scoped to a HTTP request or
Session (or indeed a custom scope of your
own devising) is all very well, but one of the main value-adds of the
Spring IoC container is that it manages not only the instantiation of
your objects (beans), but also the wiring up of collaborators (or
dependencies). If you want to inject a (for example) HTTP request
scoped bean into another bean, you will need to inject an AOP proxy in
place of the scoped bean. That is, you need to inject a proxy object
that exposes the same public interface as the scoped object, but that
is smart enough to be able to retrieve the real, target object from
the relevant scope (for example a HTTP request) and delegate method
calls onto the real object.You do not need to use the
<aop:scoped-proxy/> in conjunction with
beans that are scoped as singletons or
prototypes. It is an error to try to create a
scoped proxy for a singleton bean (and the resulting
BeanCreationException will certainly
set you straight in this regard).Let's look at the configuration that is required to effect this;
the configuration is not hugely complex (it takes just one line), but
it is important to understand the why as well as the
how behind it.<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- a HTTP Session-scoped bean exposed as a proxy -->
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
<!-- this next element effects the proxying of the surrounding bean --><aop:scoped-proxy/>
</bean>
<!-- a singleton-scoped bean injected with a proxy to the above bean -->
<bean id="userService" class="com.foo.SimpleUserService">
<!-- a reference to the proxied'userPreferences' bean -->
<property name="userPreferences" ref="userPreferences"/>
</bean>
</beans>
To create such a proxy, you need only to insert a child
<aop:scoped-proxy/> element into a scoped
bean definition (you may also need the CGLIB library on your classpath
so that the container can effect class-based proxying; you will also
need to be using ). So, just why do you
need this <aop:scoped-proxy/> element in the
definition of beans scoped at the request,
session, globalSession and
'insert your custom scope here' level? The reason
is best explained by picking apart the following bean definition
(please note that the following 'userPreferences'
bean definition as it stands is
incomplete):]]>From the above configuration it is evident that the singleton
bean 'userManager' is being injected with a
reference to the HTTP Session-scoped
bean 'userPreferences'. The salient point here is
that the 'userManager' bean is a singleton... it
will be instantiated exactly once per container,
and its dependencies (in this case only one, the
'userPreferences' bean) will also only be injected
(once!). This means that the 'userManager' will
(conceptually) only ever operate on the exact same
'userPreferences' object, that is the one that it
was originally injected with. This is not what
you want when you inject a HTTP
Session-scoped bean as a dependency
into a collaborating object (typically). Rather, what we
do want is a single
'userManager' object, and then, for the lifetime of
a HTTP Session, we want to see and use
a 'userPreferences' object that is specific to said
HTTP Session.Rather what you need then is to inject some sort of object that
exposes the exact same public interface as the
UserPreferences class (ideally an object that
is aUserPreferences
instance) and that is smart enough to be able to go off and fetch the
realUserPreferences object from whatever underlying
scoping mechanism we have chosen (HTTP request,
Session, etc.). We can then safely
inject this proxy object into the 'userManager'
bean, which will be blissfully unaware that the
UserPreferences reference that it is holding
onto is a proxy. In the case of this example, when a
UserManager instance invokes a method
on the dependency-injected UserPreferences
object, it is really invoking a method on the proxy... the proxy will
then go off and fetch the real UserPreferences
object from (in this case) the HTTP
Session, and delegate the method
invocation onto the retrieved real
UserPreferences object.That is why you need the following, correct and complete,
configuration when injecting request-,
session-, and
globalSession-scoped beans into collaborating
objects:<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
<aop:scoped-proxy/>
</bean>
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>Choosing the type of proxy createdBy default, when the Spring container is creating a proxy for
a bean that is marked up with the
<aop:scoped-proxy/> element, a
CGLIB-based class proxy will be created. This means that
you need to have the CGLIB library on the classpath of your
application.Note: CGLIB proxies will only intercept public
method calls! Do not call non-public methods on such a
proxy; they will not be delegated to the scoped target
object.You can choose to have the Spring container create 'standard'
JDK interface-based proxies for such scoped beans by specifying
'false' for the value of the
'proxy-target-class' attribute of the
<aop:scoped-proxy/> element. Using JDK
interface-based proxies does mean that you don't need any additional
libraries on your application's classpath to effect such proxying,
but it does mean that the class of the scoped bean must implement at
least one interface, and all of the
collaborators into which the scoped bean is injected must be
referencing the bean via one of its interfaces.<!-- DefaultUserPreferences implements the UserPreferences interface -->
<bean id="userPreferences" class="com.foo.DefaultUserPreferences" scope="session">
<aop:scoped-proxy proxy-target-class="false"/>
</bean>
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>The section entitled may also
be of some interest with regard to understanding the nuances of
choosing whether class-based or interface-based proxying is right
for you.Custom scopesAs of Spring 2.0, the bean scoping mechanism in Spring is
extensible. This means that you are not limited to just the bean scopes
that Spring provides out of the box; you can define your own scopes, or
even redefine the existing scopes (although that last one would probably
be considered bad practice - please note that you
cannot override the built-in
singleton and prototype
scopes).Creating your own custom scopeScopes are defined by the
org.springframework.beans.factory.config.Scope
interface. This is the interface that you will need to implement in
order to integrate your own custom scope(s) into the Spring container,
and is described in detail below. You may wish to look at the
Scope implementations that are supplied
with the Spring Framework itself for an idea of how to go about
implementing your own. The Scope
Javadoc explains the main class to implement when you need
your own scope in more detail too.The Scope interface has four methods dealing
with getting objects from the scope, removing them from the scope and
allowing them to be 'destroyed' if needed.The first method should return the object from the underlying
scope. The session scope implementation for example will return the
session-scoped bean (and if it does not exist, return a new instance
of the bean, after having bound it to the session for future
reference).The second method should remove the object from the underlying
scope. The session scope implementation for example, removes the
session-scoped bean from the underlying session. The object should be
returned (you are allowed to return null if the object with the
specified name wasn't found)The third method is used to register callbacks the scope should
execute when it is destroyed or when the specified object in the scope
is destroyed. Please refer to the Javadoc or a Spring scope
implementation for more information on destruction callbacks.The last method deals with obtaining the conversation identifier
for the underlying scope. This identifier is different for each scope.
For a session for example, this can be the session identifier.Using a custom scopeAfter you have written and tested one or more custom
Scope implementations, you then need to
make the Spring container aware of your new scope(s). The central
method to register a new Scope with the
Spring container is declared on the
ConfigurableBeanFactory interface
(implemented by most of the concrete
BeanFactory implementations that ship
with Spring); this central method is displayed below:The first argument to the
registerScope(..) method is the unique name
associated with a scope; examples of such names in the Spring
container itself are 'singleton' and
'prototype'. The second argument to the
registerScope(..) method is an actual
instance of the custom Scope
implementation that you wish to register and use.Let's assume that you have written your own custom
Scope implementation, and you have
registered it like so:// note: the ThreadScope class does not ship with the Spring Framework
Scope customScope = new ThreadScope();
beanFactory.registerScope("thread", customScope);You can then create bean definitions that adhere to the scoping
rules of your custom Scope like
so:<bean id="..." class="..." scope="thread"/>If you have your own custom Scope
implementation(s), you are not just limited to only programmatic
registration of the custom scope(s). You can also do the
Scope registration declaratively, using
the CustomScopeConfigurer class.The declarative registration of custom
Scope implementations using the
CustomScopeConfigurer class is shown
below:<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="thread">
<bean class="com.foo.ThreadScope"/>
</entry>
</map>
</property>
</bean>
<bean id="bar" class="x.y.Bar" scope="thread">
<property name="name" value="Rick"/>
<aop:scoped-proxy/>
</bean>
<bean id="foo" class="x.y.Foo">
<property name="bar" ref="bar"/>
</bean>
</beans>Note that, when placing a <aop:scoped-proxy/> in a
FactoryBean implementation, it is the
factory bean itself that is scoped, not the object returned from
getObject().Customizing the nature of a beanLifecycle callbacksThe Spring Framework provides several callback interfaces to
change the behavior of your bean in the container; they include
InitializingBean and
DisposableBean. Implementing these
interfaces will result in the container calling
afterPropertiesSet() for the former and
destroy() for the latter to allow the bean to
perform certain actions upon initialization and destruction.Internally, the Spring Framework uses
BeanPostProcessor implementations to
process any callback interfaces it can find and call the appropriate
methods. If you need custom features or other lifecycle behavior Spring
doesn't offer out-of-the-box, you can implement a
BeanPostProcessor yourself. More
information about this can be found in the section entitled .All the different lifecycle callback interfaces are described
below. In one of the appendices, you can find diagrams that show how
Spring manages beans, how those lifecycle features change the nature of
your beans, and how they are managed.Initialization callbacksImplementing the
org.springframework.beans.factory.InitializingBean
interface allows a bean to perform initialization work after all
necessary properties on the bean have been set by the container. The
InitializingBean interface specifies
exactly one method:Generally, the use of the
InitializingBean interface can be
avoided and is actually discouraged since it unnecessarily couples the
code to Spring. As an alternative, bean definitions provide support
for a generic initialization method to be specified. In the case of
XML-based configuration metadata, this is done using the
'init-method' attribute. For example, the following
definition:]]>public class ExampleBean {
public void init() {
// do some initialization work
}
}...is exactly the same as...]]>public class AnotherExampleBean implements InitializingBean {
public void afterPropertiesSet() {
// do some initialization work
}
}... but does not couple the code to Spring.Destruction callbacksImplementing the
org.springframework.beans.factory.DisposableBean
interface allows a bean to get a callback when the container
containing it is destroyed. The
DisposableBean interface specifies a
single method:Generally, the use of the
DisposableBean callback interface can
be avoided and is actually discouraged since it unnecessarily couples
the code to Spring. As an alternative, bean definitions provide
support for a generic destroy method to be specified. When using
XML-based configuration metadata this is done via the
'destroy-method' attribute on the
<bean/>. For example, the following
definition:]]>public class ExampleBean {
public void cleanup() {
// do some destruction work (like releasing pooled connections)
}
}...is exactly the same as...]]>public class AnotherExampleBean implements DisposableBean {
public void destroy() {
// do some destruction work (like releasing pooled connections)
}
}... but does not couple the code to Spring.Default initialization & destroy methodsWhen writing initialization and destroy method callbacks that do
not use the Spring-specific
InitializingBean and
DisposableBean callback interfaces, one
typically finds oneself writing methods with names such as
init(), initialize(),
dispose(), etc. The names of such lifecycle
callback methods are (hopefully!) standardized across a project so
that all developers on a team use the same method names and thus
ensure some level of consistency.The Spring container can be configured to
'look' for named initialization and destroy
callback method names on every bean. This means
that you, as an application developer, can simply write your
application classes, use a convention of having an initialization
callback called init(), and then (without having to
configure each and every bean with, in the case of XML-based
configuration, an 'init-method="init"' attribute)
be safe in the knowledge that the Spring IoC container
will call that method when the bean is being
created (and in accordance with the standard lifecycle callback
contract described previously).Let's look at an example to make the use of this feature
completely clear. For the sake of the example, let us say that one of
the coding conventions on a project is that all initialization
callback methods are to be named init() and that
destroy callback methods are to be called
destroy(). This leads to classes like so...public class DefaultBlogService implements BlogService {
private BlogDao blogDao;
public void setBlogDao(BlogDao blogDao) {
this.blogDao = blogDao;
}
// this is (unsurprisingly) the initialization callback method
public void init() {
if (this.blogDao == null) {
throw new IllegalStateException("The [blogDao] property must be set.");
}
}
}<beans default-init-method="init">
<bean id="blogService" class="com.foo.DefaultBlogService">
<property name="blogDao" ref="blogDao" />
</bean>
</beans>Notice the use of the 'default-init-method'
attribute on the top-level <beans/> element.
The presence of this attribute means that the Spring IoC container
will recognize a method called 'init' on beans as
being the initialization method callback, and when a bean is being
created and assembled, if the bean's class has such a method, it will
be invoked at the appropriate time.Destroy method callbacks are configured similarly (in XML that
is) using the 'default-destroy-method' attribute on
the top-level <beans/> element.The use of this feature can save you the (small) housekeeping
chore of specifying an initialization and destroy method callback on
each and every bean, and it is great for enforcing a consistent naming
convention for initialization and destroy method callbacks, as
consistency is something that should always be aimed for.Consider the case where you have some existing beans where the
underlying classes already have initialization callback methods that
are named at variance with the convention. You can
always override the default by specifying (in XML
that is) the method name using the 'init-method'
and 'destroy-method' attributes on the
<bean/> element itself.Finally, please be aware that the Spring container guarantees
that a configured initialization callback is called immediately after
a bean has been supplied with all of its dependencies. This means that
the initialization callback will be called on the raw bean reference,
which means that any AOP interceptors or suchlike that will ultimately
be applied to the bean will not yet be in place. A target bean is
fully created first, then an
AOP proxy (for example) with its interceptor chain is applied. Note
that, if the target bean and the proxy are defined separately, your
code can even interact with the raw target bean, bypassing the proxy.
Hence, it would be very inconsistent to apply the interceptors to the
init method, since that would couple the lifecycle of the target bean
with its proxy/interceptors and leave strange semantics when talking
to the raw target bean directly.Combining lifecycle mechanismsAs of Spring 2.5, there are three options for controlling bean
lifecycle behavior: the InitializingBean
and DisposableBean
callback interfaces; custom init() and
destroy() methods; and the @PostConstruct
and @PreDestroy
annotations.When combining different lifecycle mechanisms - for example, in
a class hierarchy in which various lifecycle mechanisms are in use -
developers should be aware of the order in which these mechanisms are
applied. The following is the ordering for initialization
methods:Methods annotated with
@PostConstructafterPropertiesSet() as defined by the
InitializingBean callback
interfaceA custom configured init() methodDestroy methods are called in the same order:Methods annotated with
@PreDestroydestroy() as defined by the
DisposableBean callback
interfaceA custom configured destroy()
methodIf multiple lifecycle mechanisms are configured for a given
bean, and each mechanism is configured with a different method name,
then each configured method will be executed in the order listed
above; however, if the same method name is configured - for example,
init() for an initialization method - for more
than one of the aforementioned lifecycle mechanisms, that method
will only be executed once.Shutting down the Spring IoC container gracefully in non-web
applicationsThis next section does not apply to web applications (in case
the title of this section did not make that abundantly clear).
Spring's web-based ApplicationContext
implementations already have code in place to handle shutting down
the Spring IoC container gracefully when the relevant web
application is being shutdown.If you are using Spring's IoC container in a non-web application
environment, for example in a rich client desktop environment, and you
want the container to shutdown gracefully and call the relevant
destroy callbacks on your singleton beans, you will need to register a
shutdown hook with the JVM. This is quite easy to do (see below), and
will ensure that your Spring IoC container shuts down gracefully and
that all resources held by your singletons are released. Of course it
is still up to you to both configure the destroy callbacks for your
singletons and implement such destroy callbacks correctly.So to register a shutdown hook that enables the graceful
shutdown of the relevant Spring IoC container, you simply need to call
the registerShutdownHook() method that is
declared on the AbstractApplicationContext
class. To wit...import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Boot {
public static void main(final String[] args) throws Exception {
AbstractApplicationContext ctx
= new ClassPathXmlApplicationContext(new String []{"beans.xml"});
// add a shutdown hook for the above context...
ctx.registerShutdownHook();
// app runs here...// main method exits, hook is called prior to the app shutting down...
}
}Knowing who you areBeanFactoryAwareA class which implements the
org.springframework.beans.factory.BeanFactoryAware
interface is provided with a reference to the
BeanFactory that created it, when it is
created by that BeanFactory.This allows beans to manipulate the
BeanFactory that created them
programmatically, through the
BeanFactory interface, or by casting
the reference to a known subclass of this which exposes additional
functionality. Primarily this would consist of programmatic retrieval
of other beans. While there are cases when this capability is useful,
it should generally be avoided, since it couples the code to Spring
and does not follow the Inversion of Control style, where
collaborators are provided to beans as properties.An alternative option that is equivalent in effect to the
BeanFactoryAware-based approach is to
use the
org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean.
(It should be noted that this approach still does not reduce the
coupling to Spring, but it does not violate the central principle of
IoC as much as the
BeanFactoryAware-based
approach.)The ObjectFactoryCreatingFactoryBean is a
FactoryBean
implementation that returns a reference to an object (factory) that
can in turn be used to effect a bean lookup. The
ObjectFactoryCreatingFactoryBean class does
itself implement the BeanFactoryAware
interface; what client beans are actually injected with is an instance
of the ObjectFactory interface. This is
a Spring-specific interface (and hence there is still no total
decoupling from Spring), but clients can then use the
ObjectFactory's
getObject() method to effect the bean lookup
(under the hood the ObjectFactory
implementation instance that is returned simply delegates down to a
BeanFactory to actually lookup a bean
by name). All that you need to do is supply the
ObjectFactoryCreatingFactoryBean with the name
of the bean that is to be looked up. Let's look at an example:Find below the XML configuration to wire together the above
classes using the
ObjectFactoryCreatingFactoryBean
approach.
]]>And here is a small driver program to test the fact that new
(prototype) instances of the newsFeed bean are
actually being returned for each call to the injected
ObjectFactory inside the
NewsFeedManager's
printNews() method.The output from running the above program will look like so
(results will of course vary on your machine).As of Spring 2.5, you can rely upon autowiring of the
BeanFactory as yet another alternative
to implementing the BeanFactoryAware
interface. The "traditional" constructor and
byType autowiring modes (as described in the
section entitled ) are now
capable of providing a dependency of type
BeanFactory for either a constructor
argument or setter method parameter respectively. For more flexibility
(including the ability to autowire fields and multiple parameter
methods), consider using the new annotation-based autowiring features.
In that case, the BeanFactory will be
autowired into a field, constructor argument, or method parameter that
is expecting the BeanFactory type as
long as the field, constructor, or method in question carries the
@Autowired annotation. For more
information, see the section entitled .BeanNameAwareIf a bean implements the
org.springframework.beans.factory.BeanNameAware
interface and is deployed in a
BeanFactory, the
BeanFactory will call the bean through
this interface to inform the bean of the name it
was deployed under. The callback will be invoked after population of
normal bean properties but before an initialization callback like
InitializingBean's
afterPropertiesSet or a custom
init-method.Bean definition inheritanceA bean definition potentially contains a large amount of
configuration information, including container specific information (for
example initialization method, static factory method name, and so forth)
and constructor arguments and property values. A child bean definition is
a bean definition that inherits configuration data from a parent
definition. It is then able to override some values, or add others, as
needed. Using parent and child bean definitions can potentially save a lot
of typing. Effectively, this is a form of templating.When working with a BeanFactory
programmatically, child bean definitions are represented by the
ChildBeanDefinition class. Most users will never
work with them on this level, instead configuring bean definitions
declaratively in something like the XmlBeanFactory.
When using XML-based configuration metadata a child bean definition is
indicated simply by using the 'parent' attribute,
specifying the parent bean as the value of this attribute.<bean id="inheritedTestBean" abstract="true"
class="org.springframework.beans.TestBean">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="inheritsWithDifferentClass"
class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBean" init-method="initialize">
<property name="name" value="override"/>
<!-- the age property value of 1 will be inherited from parent -->
</bean>A child bean definition will use the bean class from the parent
definition if none is specified, but can also override it. In the latter
case, the child bean class must be compatible with the parent, that is it
must accept the parent's property values.A child bean definition will inherit constructor argument values,
property values and method overrides from the parent, with the option to
add new values. If any init-method, destroy-method and/or
static factory method settings are specified, they will
override the corresponding parent settings.The remaining settings will always be taken
from the child definition: depends on,
autowire mode, dependency check,
singleton, scope, lazy
init.Note that in the example above, we have explicitly marked the parent
bean definition as abstract by using the abstract
attribute. In the case that the parent definition does not specify a
class, and so explicitly marking the parent bean definition as
abstract is required:<bean id="inheritedTestBeanWithoutClass" abstract="true">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBeanWithoutClass" init-method="initialize">
<property name="name" value="override"/>
<!-- age will inherit the value of 1 from the parent bean definition-->
</bean>The parent bean cannot get instantiated on its own since it is
incomplete, and it is also explicitly marked as
abstract. When a definition is defined to be
abstract like this, it is usable only as a pure
template bean definition that will serve as a parent definition for child
definitions. Trying to use such an abstract parent bean
on its own (by referring to it as a ref property of another bean, or doing
an explicit getBean() call with the parent bean
id), will result in an error. Similarly, the container's internal
preInstantiateSingletons() method will completely
ignore bean definitions which are defined as abstract.ApplicationContexts (but
notBeanFactories) will by
default pre-instantiate all singletons. Therefore it is important (at
least for singleton beans) that if you have a (parent) bean definition
which you intend to use only as a template, and this definition
specifies a class, you must make sure to set the
'abstract' attribute to
'true', otherwise the application context will
actually (attempt to) pre-instantiate the abstract
bean.Container extension pointsThe IoC component of the Spring Framework has been designed for
extension. There is typically no need for an application developer to
subclass any of the various BeanFactory or
ApplicationContext implementation classes.
The Spring IoC container can be infinitely extended by plugging in
implementations of special integration interfaces. The next few sections
are devoted to detailing all of these various integration
interfaces.Customizing beans using
BeanPostProcessorsThe first extension point that we will look at is the
BeanPostProcessor interface. This
interface defines a number of callback methods
that you as an application developer can implement in order to provide
your own (or override the containers default) instantiation logic,
dependency-resolution logic, and so forth. If you want to do some custom
logic after the Spring container has finished instantiating, configuring
and otherwise initializing a bean, you can plug in one or more
BeanPostProcessor implementations.You can configure multiple BeanPostProcessors
if you wish. You can control the order in which these
BeanPostProcessors execute by setting the
'order' property (you can only set this property if
the BeanPostProcessor implements the
Ordered interface; if you write your own
BeanPostProcessor you should consider
implementing the Ordered interface too);
consult the Javadoc for the
BeanPostProcessor and
Ordered interfaces for more
details.BeanPostProcessors operate on bean (or
object) instances; that is to say, the Spring IoC
container will have instantiated a bean instance for you, and
thenBeanPostProcessors get a
chance to do their stuff.If you want to change the actual bean definition (that is the
recipe that defines the bean), then you rather need to use a
BeanFactoryPostProcessor (described
below in the section entitled .Also, BeanPostProcessors are scoped
per-container. This is only relevant if you are
using container hierarchies. If you define a
BeanPostProcessor in one container, it
will only do its stuff on the beans in that
container. Beans that are defined in another container will not be
post-processed by BeanPostProcessors in another
container, even if both containers are part of the same
hierarchy.The
org.springframework.beans.factory.config.BeanPostProcessor
interface consists of exactly two callback methods. When such a class is
registered as a post-processor with the container (see below for how
this registration is effected), for each bean instance that is created
by the container, the post-processor will get a callback from the
container both before any container initialization
methods (such as afterPropertiesSet and any
declared init method) are called, and also afterwards. The
post-processor is free to do what it wishes with the bean instance,
including ignoring the callback completely. A bean post-processor will
typically check for callback interfaces, or do something such as wrap a
bean with a proxy; some of the Spring AOP infrastructure classes are
implemented as bean post-processors and they do this proxy-wrapping
logic.It is important to know that a
BeanFactory treats bean post-processors
slightly differently than an
ApplicationContext. An
ApplicationContext will
automatically detect any beans which are defined in
the configuration metadata which is supplied to it that implement the
BeanPostProcessor interface, and register
them as post-processors, to be then called appropriately by the
container on bean creation. Nothing else needs to be done other than
deploying the post-processors in a similar fashion to any other bean. On
the other hand, when using a BeanFactory
implementation, bean post-processors explicitly have to be registered,
with code like this:ConfigurableBeanFactory factory = new XmlBeanFactory(...);
// now register any needed BeanPostProcessor instances
MyBeanPostProcessor postProcessor = new MyBeanPostProcessor();
factory.addBeanPostProcessor(postProcessor);
// now start using the factoryThis explicit registration step is not convenient, and this is one
of the reasons why the various
ApplicationContext implementations are
preferred above plain BeanFactory
implementations in the vast majority of Spring-backed applications,
especially when using BeanPostProcessors.BeanPostProcessors and AOP
auto-proxyingClasses that implement the
BeanPostProcessor interface are
special, and so they are treated differently by
the container. All BeanPostProcessorsand their directly referenced beans will be
instantiated on startup, as part of the special startup phase of the
ApplicationContext,
then all those
BeanPostProcessors will be registered
in a sorted fashion - and applied to all further beans. Since AOP
auto-proxying is implemented as a
BeanPostProcessor itself, no
BeanPostProcessors or directly
referenced beans are eligible for auto-proxying (and thus will not
have aspects 'woven' into them.For any such bean, you should see an info log message:
Bean 'foo' is not eligible for getting processed by
all BeanPostProcessors (for example: not eligible for
auto-proxying).Find below some examples of how to write, register, and use
BeanPostProcessors in the context of an
ApplicationContext.Example: Hello World,
BeanPostProcessor-styleThis first example is hardly compelling, but serves to
illustrate basic usage. All we are going to do is code a custom
BeanPostProcessor implementation that
simply invokes the toString() method of each
bean as it is created by the container and prints the resulting string
to the system console. Yes, it is not hugely useful, but serves to get
the basic concepts across before we move into the second example which
is actually useful.Find below the custom
BeanPostProcessor implementation class
definition:package scripting;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.BeansException;
public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {
// simply return the instantiated bean as-is
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean; // we could potentially return any object reference here...
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean '" + beanName + "' created : " + bean.toString());
return bean;
}
}<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/lang
http://www.springframework.org/schema/lang/spring-lang-3.0.xsd">
<lang:groovy id="messenger"
script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy">
<lang:property name="message" value="Fiona Apple Is Just So Dreamy."/>
</lang:groovy>
<!--
when the above bean ('messenger') is instantiated, this custom
BeanPostProcessor implementation will output the fact to the system console
-->
<bean class="scripting.InstantiationTracingBeanPostProcessor"/>
</beans>Notice how the
InstantiationTracingBeanPostProcessor is simply
defined; it doesn't even have a name, and because it is a bean it can
be dependency injected just like any other bean. (The above
configuration also just so happens to define a bean that is backed by
a Groovy script. The Spring 2.0 dynamic language support is detailed
in the chapter entitled .)Find below a small driver script to exercise the above code and
configuration;The output of executing the above program will be (something
like) this:Example: The
RequiredAnnotationBeanPostProcessorUsing callback interfaces or annotations in conjunction with a
custom BeanPostProcessor implementation
is a common means of extending the Spring IoC container. This next
example is a bit of a cop-out, in that you are directed to the section
entitled which
demonstrates the usage of a custom
BeanPostProcessor implementation that
ships with the Spring distribution which ensures that JavaBean
properties on beans that are marked with an (arbitrary) annotation are
actually (configured to be) dependency-injected with a value.Customizing configuration metadata with
BeanFactoryPostProcessorsThe next extension point that we will look at is the
org.springframework.beans.factory.config.BeanFactoryPostProcessor.
The semantics of this interface are similar to the
BeanPostProcessor, with one major
difference: BeanFactoryPostProcessors operate on the
bean configuration metadata; that is, the Spring
IoC container will allow BeanFactoryPostProcessors to
read the configuration metadata and potentially change it
before the container has actually instantiated any
other beans.You can configure multiple
BeanFactoryPostProcessors if you wish. You can
control the order in which these
BeanFactoryPostProcessors execute by setting the
'order' property (you can only set this property if
the BeanFactoryPostProcessor implements
the Ordered interface; if you write your
own BeanFactoryPostProcessor you should
consider implementing the Ordered
interface too); consult the Javadoc for the
BeanFactoryPostProcessor and
Ordered interfaces for more
details.If you want to change the actual bean
instances (the objects that are created from the
configuration metadata), then you rather need to use a
BeanPostProcessor (described above in
the section entitled .Also, BeanFactoryPostProcessors are scoped
per-container. This is only relevant if you are
using container hierarchies. If you define a
BeanFactoryPostProcessor in one
container, it will only do its stuff on the bean
definitions in that container. Bean definitions in another container
will not be post-processed by
BeanFactoryPostProcessors in another container,
even if both containers are part of the same hierarchy.A bean factory post-processor is executed manually (in the case of
a BeanFactory) or automatically (in the
case of an ApplicationContext) to apply
changes of some sort to the configuration metadata that defines a
container. Spring includes a number of pre-existing bean factory
post-processors, such as
PropertyOverrideConfigurer and
PropertyPlaceholderConfigurer, both described
below. A custom BeanFactoryPostProcessor
can also be used to register custom property editors, for
example.In a BeanFactory, the process of
applying a BeanFactoryPostProcessor is
manual, and will be similar to this:XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));
// bring in some property values from a Properties file
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("jdbc.properties"));
// now actually do the replacement
cfg.postProcessBeanFactory(factory);This explicit registration step is not convenient, and this is one
of the reasons why the various
ApplicationContext implementations are
preferred above plain BeanFactory
implementations in the vast majority of Spring-backed applications,
especially when using
BeanFactoryPostProcessors.An ApplicationContext will detect
any beans which are deployed into it which implement the
BeanFactoryPostProcessor interface, and
automatically use them as bean factory post-processors, at the
appropriate time. Nothing else needs to be done other than deploying
these post-processor in a similar fashion to any other bean.Just as in the case of BeanPostProcessors,
you typically don't want to have
BeanFactoryPostProcessors marked as being
lazily-initialized. If they are marked as such, then the Spring
container will never instantiate them, and thus they won't get a
chance to apply their custom logic. If you are using the
'default-lazy-init' attribute on the declaration of
your <beans/> element, be sure to mark your
various BeanFactoryPostProcessor bean
definitions with 'lazy-init="false"'.Example: the
PropertyPlaceholderConfigurerThe PropertyPlaceholderConfigurer
is used to externalize property values from a
BeanFactory definition, into another
separate file in the standard Java Properties
format. This is useful to allow the person deploying an application to
customize environment-specific properties (for example database URLs,
usernames and passwords), without the complexity or risk of modifying
the main XML definition file or files for the container.Consider the following XML-based configuration metadata
fragment, where a DataSource with
placeholder values is defined. We will configure some properties from
an external Properties file, and at runtime, we
will apply a PropertyPlaceholderConfigurer to
the metadata which will replace some properties of the
DataSource:<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:com/foo/jdbc.properties</value>
</property>
</bean>
<bean id="dataSource" destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>The actual values come from another file in the standard Java
Properties format:With the context namespace introduced in
Spring 2.5, it is possible to configure property placeholders with a
dedicated configuration element. Multiple locations may be provided as
a comma-separated list for the location
attribute.]]>The PropertyPlaceholderConfigurer doesn't
only look for properties in the Properties file
you specify, but also checks against the Java
System properties if it cannot find a property
you are trying to use. This behavior can be customized by setting the
systemPropertiesMode property of the configurer. It
has three values, one to tell the configurer to always override, one
to let it never override and one to let it
override only if the property cannot be found in the properties file
specified. Please consult the Javadoc for the
PropertyPlaceholderConfigurer for more
information.Class name substitutionThe PropertyPlaceholderConfigurer can
be used to substitute class names, which is sometimes useful when
you have to pick a particular implementation class at runtime. For
example:classpath:com/foo/strategy.propertiescustom.strategy.class=com.foo.DefaultStrategy]]>If the class is unable to be resolved at runtime to a valid
class, resolution of the bean will fail once it is about to be
created (which is during the
preInstantiateSingletons() phase of an
ApplicationContext for a
non-lazy-init bean.)Example: the
PropertyOverrideConfigurerThe PropertyOverrideConfigurer, another
bean factory post-processor, is similar to the
PropertyPlaceholderConfigurer, but in
contrast to the latter, the original definitions can have default
values or no values at all for bean properties. If an overriding
Properties file does not have an entry for a
certain bean property, the default context definition is used.Note that the bean factory definition is
not aware of being overridden, so it is not
immediately obvious when looking at the XML definition file that the
override configurer is being used. In case that there are multiple
PropertyOverrideConfigurer instances that
define different values for the same bean property, the last one will
win (due to the overriding mechanism).Properties file configuration lines are expected to be in the
format:An example properties file might look like this:This example file would be usable against a container definition
which contains a bean called dataSource, which
has driver and url
properties.Note that compound property names are also supported, as long as
every component of the path except the final property being overridden
is already non-null (presumably initialized by the constructors). In
this example...... the sammy property of the
bob property of the fred
property of the foo bean is being set to the scalar
value 123.Note: Specified override values are always
literal values; they are not translated into bean
references. This also applies when the original value in the XML bean
definition specifies a bean referenceWith the context namespace introduced in
Spring 2.5, it is possible to configure property overriding with a
dedicated configuration element:]]>Customizing instantiation logic using
FactoryBeansThe
org.springframework.beans.factory.FactoryBean
interface is to be implemented by objects that are themselves
factories.The FactoryBean interface is a
point of pluggability into the Spring IoC containers instantiation
logic. If you have some complex initialization code that is better
expressed in Java as opposed to a (potentially) verbose amount of XML,
you can create your own FactoryBean,
write the complex initialization inside that class, and then plug your
custom FactoryBean into the
container.The FactoryBean interface provides
three methods:Object getObject(): has to return an
instance of the object this factory creates. The instance can
possibly be shared (depending on whether this factory returns
singletons or prototypes).boolean isSingleton(): has to return
true if this
FactoryBean returns singletons,
false otherwiseClass getObjectType(): has to return
either the object type returned by the
getObject() method or
null if the type isn't known in advanceThe FactoryBean concept and
interface is used in a number of places within the Spring Framework; at
the time of writing there are over 50 implementations of the
FactoryBean interface that ship with
Spring itself.Finally, there is sometimes a need to ask a container for an
actual FactoryBean instance itself, not
the bean it produces. This may be achieved by prepending the bean id
with '&' (sans quotes) when calling the
getBean method of the
BeanFactory (including
ApplicationContext). So for a given
FactoryBean with an id of
myBean, invoking getBean("myBean")
on the container will return the product of the
FactoryBean, but invoking
getBean("&myBean") will return the
FactoryBean instance itself.The ApplicationContextWhile the beans package provides basic
functionality for managing and manipulating beans, including in a
programmatic way, the context package adds the ApplicationContext
interface, which enhances BeanFactory
functionality in a more framework-oriented style.
Many users will use ApplicationContext in a
completely declarative fashion, not even having to create it manually, but
instead relying on support classes such as
ContextLoader to automatically instantiate an
ApplicationContext as part of the normal
startup process of a J2EE web-app. (Of course, it is still possible to
create an ApplicationContext
programmatically.)The basis for the context package is the
ApplicationContext interface, located in
the org.springframework.context package. Deriving from
the BeanFactory interface, it provides all
the functionality of BeanFactory. To allow
working in a more framework-oriented fashion, using layering and
hierarchical contexts, the context package also provides the following
functionality:MessageSource, providing access
to messages in i18n-style.Access to resources, such as URLs and
files.Event propagation to beans implementing the
ApplicationListener interface.Loading of multiple (hierarchical)
contexts, allowing each to be focused on one particular
layer, for example the web layer of an application.BeanFactory or
ApplicationContext?Short version: use an
ApplicationContext unless you have a
really good reason for not doing so. For those of you that are looking
for slightly more depth as to the 'but why' of the above recommendation,
keep reading.As the ApplicationContext includes
all functionality of the BeanFactory, it
is generally recommended that it be used in preference to the
BeanFactory, except for a few limited
situations such as in an Applet, where memory
consumption might be critical and a few extra kilobytes might make a
difference. However, for most 'typical' enterprise applications and
systems, the ApplicationContext is what
you will want to use. Versions of Spring 2.0 and above make
heavy use of the BeanPostProcessor
extension point (to effect proxying and suchlike), and if you are
using just a plain BeanFactory then a
fair amount of support such as transactions and AOP will not take effect
(at least not without some extra steps on your part), which could be
confusing because nothing will actually be wrong with the
configuration.Find below a feature matrix that lists what features are provided
by the BeanFactory and
ApplicationContext interfaces (and
attendant implementations). (The following sections describe
functionality that ApplicationContext
adds to the basic BeanFactory
capabilities in a lot more depth than the said feature matrix.)
Internationalization using
MessageSourcesThe ApplicationContext interface
extends an interface called
MessageSource, and therefore provides
messaging (i18n or internationalization) functionality. Together with
the HierarchicalMessageSource, capable of
resolving hierarchical messages, these are the basic interfaces Spring
provides to do message resolution. Let's quickly review the methods
defined there:String getMessage(String code, Object[] args,
String default, Locale loc): the basic method used to
retrieve a message from the
MessageSource. When no message is
found for the specified locale, the default message is used. Any
arguments passed in are used as replacement values, using the
MessageFormat functionality provided
by the standard library.String getMessage(String code, Object[] args,
Locale loc): essentially the same as the previous
method, but with one difference: no default message can be
specified; if the message cannot be found, a
NoSuchMessageException is thrown.String getMessage(MessageSourceResolvable
resolvable, Locale locale): all properties used in the
methods above are also wrapped in a class named
MessageSourceResolvable, which you
can use via this method.When an ApplicationContext gets
loaded, it automatically searches for a
MessageSource bean defined in the
context. The bean has to have the name
'messageSource'. If such a bean is found, all calls
to the methods described above will be delegated to the message source
that was found. If no message source was found, the
ApplicationContext attempts to see if it
has a parent containing a bean with the same name. If so, it uses that
bean as the MessageSource. If it can't
find any source for messages, an empty
DelegatingMessageSource will be instantiated in
order to be able to accept calls to the methods defined above.Spring currently provides two
MessageSource implementations. These are
the ResourceBundleMessageSource and the
StaticMessageSource. Both implement
HierarchicalMessageSource in order to do
nested messaging. The StaticMessageSource is
hardly ever used but provides programmatic ways to add messages to the
source. The ResourceBundleMessageSource is more
interesting and is the one we will provide an example for:formatexceptionswindows
]]>This assumes you have three resource bundles defined on your
classpath called format,
exceptions and windows. Using the
JDK standard way of resolving messages through ResourceBundles, any
request to resolve a message will be handled. For the purposes of the
example, lets assume the contents of two of the above resource bundle
files are...# in 'format.properties'
message=Alligators rock!# in 'exceptions.properties'
argument.required=The '{0}' argument is required.Some (admittedly trivial) driver code to exercise the
MessageSource functionality can be found below.
Remember that all ApplicationContext
implementations are also MessageSource
implementations and so can be cast to the
MessageSource interface.The resulting output from the above program will be...So to summarize, the MessageSource is
defined in a file called 'beans.xml' (this file
exists at the root of your classpath). The
'messageSource' bean definition refers to a number of
resource bundles via its basenames property; the
three files that are passed in the list to the
basenames property exist as files at the root of your
classpath (and are called format.properties,
exceptions.properties, and
windows.properties respectively).Lets look at another example, and this time we will look at
passing arguments to the message lookup; these arguments will be
converted into Strings and inserted into placeholders in the lookup
message. This is perhaps best explained with an example:<beans>
<!-- this MessageSource is being used in a web application -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="test-messages"/>
</bean>
<!-- let's inject the above MessageSource into this POJO -->
<bean id="example" class="com.foo.Example">
<property name="messages" ref="messageSource"/>
</bean>
</beans>The resulting output from the invocation of the
execute() method will be...With regard to internationalization (i18n), Spring's various
MessageResource implementations follow the same
locale resolution and fallback rules as the standard JDK
ResourceBundle. In short, and continuing with the
example 'messageSource' defined previously, if you
want to resolve messages against the British (en-GB) locale, you would
create files called format_en_GB.properties,
exceptions_en_GB.properties, and
windows_en_GB.properties respectively.Locale resolution is typically going to be managed by the
surrounding environment of the application. For the purpose of this
example though, we'll just manually specify the locale that we want to
resolve our (British) messages against.# in 'exceptions_en_GB.properties'
argument.required=Ebagum lad, the '{0}' argument is required, I say, required.The resulting output from the running of the above program will
be...The MessageSourceAware interface can also
be used to acquire a reference to any
MessageSource that has been defined. Any bean
that is defined in an ApplicationContext that
implements the MessageSourceAware interface will
be injected with the application context's
MessageSource when it (the bean) is being created
and configured.Note: As an alternative to
ResourceBundleMessageSource, Spring also provides
a ReloadableResourceBundleMessageSource class.
This variant supports the same bundle file format but is more flexible
than the standard JDK based
ResourceBundleMessageSource
implementation. In particular, it allows for reading files
from any Spring resource location (not just from the classpath) and
supports hot reloading of bundle property files (while efficiently
caching them in between). Check out the
ReloadableResourceBundleMessageSource javadoc for
details.EventsEvent handling in the
ApplicationContext is provided through
the ApplicationEvent class and
ApplicationListener interface. If a bean
which implements the ApplicationListener
interface is deployed into the context, every time an
ApplicationEvent gets published to the
ApplicationContext, that bean will be
notified. Essentially, this is the standard
Observer design pattern. Spring provides the
following standard events:
Built-in EventsEventExplanationContextRefreshedEventPublished when the
ApplicationContext is initialized
or refreshed, e.g. using the refresh()
method on the
ConfigurableApplicationContext
interface. "Initialized" here means that all beans are loaded,
post-processor beans are detected and activated, singletons are
pre-instantiated, and the
ApplicationContext object is
ready for use. A refresh may be triggered multiple times, as
long as the context hasn't been closed - provided that the
chosen ApplicationContext
actually supports such "hot" refreshes (which e.g.
XmlWebApplicationContext does but
GenericApplicationContext
doesn't).ContextStartedEventPublished when the
ApplicationContext is started,
using the start() method on the
ConfigurableApplicationContext
interface. "Started" here means that all
Lifecycle beans will receive an
explicit start signal. This will typically be used for
restarting after an explicit stop, but may also be used for
starting components that haven't been configured for autostart
(e.g. haven't started on initialization already).ContextStoppedEventPublished when the
ApplicationContext is stopped,
using the stop() method on the
ConfigurableApplicationContext
interface. "Stopped" here means that all
Lifecycle beans will receive an
explicit stop signal. A stopped context may be restarted through
a start() call.ContextClosedEventPublished when the
ApplicationContext is closed,
using the close() method on the
ConfigurableApplicationContext
interface. "Closed" here means that all singleton beans are
destroyed. A closed context has reached its end of life; it
cannot be refreshed or restarted.RequestHandledEventA web-specific event telling all beans that an HTTP
request has been serviced (this will be published
after the request has been finished). Note
that this event is only applicable for web applications using
Spring's DispatcherServlet.
Implementing custom events can be done as well. Simply call the
publishEvent() method on the
ApplicationContext, specifying a
parameter which is an instance of your custom event class implementing
ApplicationEvent. Event listeners receive events
synchronously. This means the publishEvent()
method blocks until all listeners have finished processing the event (it
is possible to supply an alternate event publishing strategy via a
ApplicationEventMulticaster
implementation). Furthermore, when a listener receives an event it
operates inside the transaction context of the publisher, if a
transaction context is available.Let's look at an example. First, the
ApplicationContext:black@list.orgwhite@list.orgjohn@doe.org]]>Now, let's look at the actual classes:public class EmailBean implements ApplicationContextAware {
private List blackList;
private ApplicationContext ctx;
public void setBlackList(List blackList) {
this.blackList = blackList;
}
public void setApplicationContext(ApplicationContext ctx) {
this.ctx = ctx;
}
public void sendEmail(String address, String text) {
if (blackList.contains(address)) {
BlackListEvent event = new BlackListEvent(address, text);
ctx.publishEvent(event);
return;
}
// send email...
}
}public class BlackListNotifier implements ApplicationListener {
private String notificationAddress;
public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress;
}
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof BlackListEvent) {
// notify appropriate person...
}
}
}Of course, this particular example could probably be implemented
in better ways (perhaps by using AOP features), but it should be
sufficient to illustrate the basic event mechanism.Convenient access to low-level resourcesFor optimal usage and understanding of application contexts, users
should generally familiarize themselves with Spring's
Resource abstraction, as described in the
chapter entitled .An application context is a
ResourceLoader, able to be used to load
Resources. A
Resource is essentially a
java.net.URL on steroids (in fact, it just wraps and
uses a URL where appropriate), which can be used to obtain low-level
resources from almost any location in a transparent fashion, including
from the classpath, a filesystem location, anywhere describable with a
standard URL, and some other variations. If the resource location string
is a simple path without any special prefixes, where those resources
come from is specific and appropriate to the actual application context
type.A bean deployed into the application context may implement the
special callback interface,
ResourceLoaderAware, to be automatically
called back at initialization time with the application context itself
passed in as the ResourceLoader. A bean
may also expose properties of type
Resource, to be used to access static
resources, and expect that they will be injected into it like any other
properties. The person deploying the bean may specify those
Resource properties as simple String
paths, and rely on a special JavaBean
PropertyEditor that is automatically
registered by the context, to convert those text strings to actual
Resource objects.The location path or paths supplied to an
ApplicationContext constructor are
actually resource strings, and in simple form are treated appropriately
to the specific context implementation (
ClassPathXmlApplicationContext treats a simple
location path as a classpath location), but may also be used with
special prefixes to force loading of definitions from the classpath or a
URL, regardless of the actual context type.Convenient ApplicationContext
instantiation for web applicationsAs opposed to the BeanFactory,
which will often be created programmatically,
ApplicationContext instances can be
created declaratively using for example a
ContextLoader. Of course you can also create
ApplicationContext instances
programmatically using one of the
ApplicationContext implementations.
First, let's examine the ContextLoader mechanism
and its implementations.The ContextLoader mechanism comes in two
flavors: the ContextLoaderListener and the
ContextLoaderServlet. They both have the same
functionality but differ in that the listener version cannot be reliably
used in Servlet 2.3 containers. Since the Servlet 2.4 specification,
servlet context listeners are required to execute immediately after the
servlet context for the web application has been created and is
available to service the first request (and also when the servlet
context is about to be shut down): as such a servlet context listener is
an ideal place to initialize the Spring
ApplicationContext. It is up to you as to
which one you use, but all things being equal you should probably prefer
ContextLoaderListener; for more information on
compatibility, have a look at the Javadoc for the
ContextLoaderServlet.You can register an
ApplicationContext using the
ContextLoaderListener as follows:<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- or use the ContextLoaderServlet instead of the above listener
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
-->The listener inspects the
'contextConfigLocation' parameter. If the parameter
does not exist, the listener will use
/WEB-INF/applicationContext.xml as a default. When it
does exist, it will separate the String using
predefined delimiters (comma, semicolon and whitespace) and use the
values as locations where application contexts will be searched for.
Ant-style path patterns are supported as well: e.g.
/WEB-INF/*Context.xml (for all files whose name ends
with "Context.xml", residing in the "WEB-INF" directory) or
/WEB-INF/**/*Context.xml (for all such files in any
subdirectory of "WEB-INF").The ContextLoaderServlet can be used
instead of the ContextLoaderListener. The servlet
will use the 'contextConfigLocation' parameter just
as the listener does.Glue code and the evil singletonThe majority of the code inside an application is best written in a
DI style, where that code is served out of a Spring IoC container, has its
own dependencies supplied by the container when it is created, and is
completely unaware of the container. However, for the small glue layers of
code that are sometimes needed to tie other code together, there is
sometimes a need for singleton (or quasi-singleton) style access to a
Spring IoC container. For example, third party code may try to construct
new objects directly (Class.forName() style), without
the ability to force it to get these objects out of a Spring IoC
container. If the object constructed by the third party code is just a
small stub or proxy, which then uses a singleton style access to a Spring
IoC container to get a real object to delegate to, then inversion of
control has still been achieved for the majority of the code (the object
coming out of the container); thus most code is still unaware of the
container or how it is accessed, and remains decoupled from other code,
with all ensuing benefits. EJBs may also use this stub/proxy approach to
delegate to a plain Java implementation object, coming out of a Spring IoC
container. While the Spring IoC container itself ideally does not have to
be a singleton, it may be unrealistic in terms of memory usage or
initialization times (when using beans in the Spring IoC container such as
a Hibernate SessionFactory) for each bean
to use its own, non-singleton Spring IoC container.As another example, in complex J2EE applications with multiple
layers (various JAR files, EJBs, and WAR files packaged as an EAR), with
each layer having its own Spring IoC container definition (effectively
forming a hierarchy), the preferred approach when there is only one
web-app (WAR) in the top hierarchy is to simply create one composite
Spring IoC container from the multiple XML definition files from each
layer. All of the various Spring IoC container implementations may be
constructed from multiple definition files in this fashion. However, if
there are multiple sibling web-applications at the root of the hierarchy,
it is problematic to create a Spring IoC container for each
web-application which consists of mostly identical bean definitions from
lower layers, as there may be issues due to increased memory usage, issues
with creating multiple copies of beans which take a long time to
initialize (for example a Hibernate
SessionFactory), and possible issues due to
side-effects. As an alternative, classes such as ContextSingletonBeanFactoryLocator
or SingletonBeanFactoryLocator
may be used to demand-load multiple hierarchical (that is one container is
the parent of another) Spring IoC container instances in a singleton
fashion, which may then be used as the parents of the web-application
Spring IoC container instances. The result is that bean definitions for
lower layers are loaded only as needed, and loaded only once.You can see a detailed example of the usage of these classes by
viewing the Javadoc for the SingletonBeanFactoryLocator
and ContextSingletonBeanFactoryLocator
classes. As mentioned in the chapter on EJBs,
the Spring convenience base classes for EJBs normally use a non-singleton
BeanFactoryLocator implementation, which is
easily replaced by the use of
SingletonBeanFactoryLocator and
ContextSingletonBeanFactoryLocator.Deploying a Spring ApplicationContext as a J2EE RAR fileSince Spring 2.5, it is possible to deploy a Spring
ApplicationContext as a RAR file, encapsulating the context and all of its
required bean classes and library JARs in a J2EE RAR deployment unit. This
is the equivalent of bootstrapping a standalone ApplicationContext, just
hosted in J2EE environment, being able to access the J2EE server's
facilities. RAR deployment is intended as a more 'natural' alternative to
the not uncommon scenario of deploying a headless WAR file - i.e. a WAR
file without any HTTP entry points, just used for bootstrapping a Spring
ApplicationContext in a J2EE environment.RAR deployment is ideal for application contexts that do not need
any HTTP entry points but rather just consist of message endpoints and
scheduled jobs etc. Beans in such a context may use application server
resources such as the JTA transaction manager and JNDI-bound JDBC
DataSources and JMS ConnectionFactory instances, and may also register
with the platform's JMX server - all through Spring's standard transaction
management and JNDI and JMX support facilities. Application components may
also interact with the application's server JCA WorkManager through
Spring's TaskExecutor abstraction.Check out the JavaDoc of the SpringContextResourceAdapter
class for the configuration details involved in RAR deployment.For simple deployment needs, all you need to do is the
following: Package all application classes into a RAR file
(which is just a standard JAR file with a different file extension), add
all required library jars into the root of the RAR archive, add a
"META-INF/ra.xml" deployment descriptor (as shown in
SpringContextResourceAdapter's JavaDoc) as well as
the corresponding Spring XML bean definition file(s) (typically
"META-INF/applicationContext.xml"), and drop the resulting RAR file into
your application server's deployment directory!NOTE: Such RAR deployment units are usually
self-contained; they do not expose components to the 'outside' world, not
even to other modules of the same application. Interaction with a
RAR-based ApplicationContext usually happens through JMS destinations that
it shares with other modules. A RAR-based ApplicationContext may also -
for example - schedule some jobs, reacting to new files in the file system
(or the like). If it actually needs to allow for synchronous access from
the outside, it could for example export RMI endpoints, which of course
may be used by other application modules on the same machine as
well.Annotation-based configurationAs mentioned in the section entitled , using a
BeanPostProcessor in conjunction with
annotations is a common means of extending the Spring IoC container. For
example, Spring 2.0 introduced the possibility of enforcing required
properties with the @Required annotation. As of
Spring 2.5, it is now possible to follow that same general approach to
drive Spring's dependency injection. Essentially, the
@Autowired annotation provides the same
capabilities as described in but
with more fine-grained control and wider applicability. Spring 2.5 also
adds support for JSR-250 annotations such as
@Resource,
@PostConstruct, and
@PreDestroy. Of course, these options are
only available if you are using at least Java 5 (Tiger) and thus have
access to source level annotations. Use of these annotations also requires
that certain BeanPostProcessors be
registered within the Spring container. As always, these can be registered
as individual bean definitions, but they can also be implicitly registered
by including the following tag in an XML-based Spring configuration
(notice the inclusion of the 'context'
namespace):<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
</beans>(The implicitly registered post-processors include AutowiredAnnotationBeanPostProcessor,
CommonAnnotationBeanPostProcessor,
PersistenceAnnotationBeanPostProcessor,
as well as the aforementioned RequiredAnnotationBeanPostProcessor.)Note that <context:annotation-config/>
only looks for annotations on beans in the same application context it
is defined in. This means that, if you put
<context:annotation-config/> in a
WebApplicationContext for a
DispatcherServlet, it only checks for
@Autowired beans in your controllers, and
not your services. See for more
information.@RequiredThe @Required annotation applies to
bean property setter methods, as in the following example:public class SimpleMovieLister {
private MovieFinder movieFinder;
@Required
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}This annotation simply indicates that the affected bean property
must be populated at configuration time: either through an explicit
property value in a bean definition or through autowiring. The container
will throw an exception if the affected bean property has not been
populated; this allows for eager and explicit failure, avoiding
NullPointerExceptions or the like later on. Note
that it is still recommended to put assertions into the bean class
itself (for example into an init method) in order to enforce those
required references and values even when using the class outside of a
container.@AutowiredAs expected, the @Autowired
annotation may be applied to "traditional" setter methods:public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}The annotation may also be applied to methods with arbitrary names
and/or multiple arguments:public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}The @Autowired annotation may even
be applied on constructors and fields:public class MovieRecommender {
@Autowired
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}It is also possible to provide all beans of a
particular type from the
ApplicationContext by adding the
annotation to a field or method that expects an array of that
type:public class MovieRecommender {
@Autowired
private MovieCatalog[] movieCatalogs;
// ...
}The same applies for typed collections:public class MovieRecommender {
private Set<MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}Even typed Maps may be autowired as long as the expected key type
is String. The Map values will contain all beans
of the expected type, and the keys will contain the corresponding bean
names:public class MovieRecommender {
private Map<String, MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}By default, the autowiring will fail whenever
zero candidate beans are available; the default
behavior is to treat annotated methods, constructors, and fields as
indicating required dependencies. This behavior can
be changed as demonstrated below.public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired(required=false)
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}Only one annotated constructor per-class
may be marked as required, but multiple
non-required constructors can be annotated. In that case, each will be
considered among the candidates and Spring will use the
greediest constructor whose dependencies can be
satisfied.Prefer the use of @Autowired's
required attribute over the
@Required annotation. The
required attribute indicates that the property is
not required for autowiring purposes, simply skipping it if it cannot
be autowired. @Required, on the other
hand, is stronger in that it enforces the property to have been set in
any of the container's supported ways; if no value has been injected,
a corresponding exception will be raised.@Autowired may also be used for
well-known "resolvable dependencies": the
BeanFactory interface, the
ApplicationContext interface, the
ResourceLoader interface, the
ApplicationEventPublisher interface and
the MessageSource interface. These
interfaces (and their extended interfaces such as
ConfigurableApplicationContext or
ResourcePatternResolver) will be
automatically resolved, with no special setup necessary.public class MovieRecommender {
@Autowired
private ApplicationContext context;
public MovieRecommender() {
}
// ...
}Fine-tuning annotation-based autowiring with qualifiersSince autowiring by type may lead to multiple candidates, it is
often necessary to have more control over the selection process. One way
to accomplish this is with Spring's
@Qualifier annotation. This allows for
associating qualifier values with specific arguments, narrowing the set
of type matches so that a specific bean is chosen for each argument. In
the simplest case, this can be a plain descriptive value:public class MovieRecommender {
@Autowired
@Qualifier("main")
private MovieCatalog movieCatalog;
// ...
}The @Qualifier annotation can also
be specified on individual constructor arguments or method
parameters:public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(@Qualifier("main") MovieCatalog movieCatalog, CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}The corresponding bean definitions would look like as follows. The
bean with qualifier value "main" would be wired with the constructor
argument that has been qualified with the same value.<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog">
<qualifier value="main"/><!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier value="action"/><!-- inject any dependencies required by this bean -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
For a fallback match, the bean name is considered as a default
qualifier value. This means that the bean may be defined with an id
"main" instead of the nested qualifier element, leading to the same
matching result. However, note that while this can be used to refer to
specific beans by name, @Autowired is
fundamentally about type-driven injection with optional semantic
qualifiers. This means that qualifier values, even when using the bean
name fallback, always have narrowing semantics within the set of type
matches; they do not semantically express a reference to a unique bean
id. Good qualifier values would be "main" or "EMEA" or "persistent",
expressing characteristics of a specific component - independent from
the bean id (which may be auto-generated in case of an anonymous bean
definition like the one above).Qualifiers also apply to typed collections (as discussed above):
e.g. to Set<MovieCatalog>. In such a case, all
matching beans according to the declared qualifiers are going to be
injected as a collection. This implies that qualifiers do not have to be
unique; they rather simply constitute filtering criteria. For example,
there could be multiple MovieCatalog beans
defined with the same qualifier value "action"; all of which would be
injected into a Set<MovieCatalog> annotated
with @Qualifier("action").If you intend to express annotation-driven injection by name, do
not primarily use @Autowired - even if
is technically capable of referring to a bean name through
@Qualifier values. Instead, prefer the
JSR-250 @Resource annotation which is
semantically defined to identify a specific target component by its
unique name, with the declared type being irrelevant for the matching
process.As a specific consequence of this semantic difference, beans
which are themselves defined as a collection or map type cannot be
injected via @Autowired since type
matching is not properly applicable to them. Use
@Resource for such beans, referring to
the specific collection/map bean by unique name.Note: In contrast to
@Autowired which is applicable to
fields, constructors and multi-argument methods (allowing for
narrowing through qualifier annotations at the parameter level),
@Resource is only supported for fields
and bean property setter methods with a single argument. As a
consequence, stick with qualifiers if your injection target is a
constructor or a multi-argument method.You may create your own custom qualifier annotations as well.
Simply define an annotation and provide the
@Qualifier annotation within your
definition:@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {
String value();
}Then you can provide the custom qualifier on autowired fields and
parameters:public class MovieRecommender {
@Autowired
@Genre("Action")
private MovieCatalog actionCatalog;
private MovieCatalog comedyCatalog;
@Autowired
public void setComedyCatalog(@Genre("Comedy") MovieCatalog comedyCatalog) {
this.comedyCatalog = comedyCatalog;
}
// ...
}The next step is to provide the information on the candidate bean
definitions. You can add <qualifier/> tags as
sub-elements of the <bean/> tag and then
specify the 'type' and 'value' to
match your custom qualifier annotations. The type will be matched
against the fully-qualified class name of the annotation, or as a
convenience when there is no risk of conflicting names, you may use the
'short' class name. Both are demonstrated in the following
example.<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog">
<qualifier type="Genre" value="Action"/><!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier type="example.Genre" value="Comedy"/><!-- inject any dependencies required by this bean -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
In the next section, entitled , you will see an annotation-based
alternative to providing the qualifier metadata in XML. Specifically,
see: .In some cases, it may be sufficient to use an annotation without a
value. This may be useful when the annotation serves a more generic
purpose and could be applied across several different types of
dependencies. For example, you may provide an
offline catalog that would be searched when no
Internet connection is available. First define the simple
annotation:Then add the annotation to the field or property to be
autowired:public class MovieRecommender {
@Autowired
@Offline
private MovieCatalog offlineCatalog;
// ...
}Now the bean definition only needs a qualifier
'type':<bean class="example.SimpleMovieCatalog">
<qualifier type="Offline"/><!-- inject any dependencies required by this bean -->
</bean>It is also possible to define custom qualifier annotations that
accept named attributes in addition to or instead of the simple
'value' attribute. If multiple attribute values are
then specified on a field or parameter to be autowired, a bean
definition must match all such attribute values to
be considered an autowire candidate. As an example, consider the
following annotation definition:In this case Format is an enum:The fields to be autowired are annotated with the custom qualifier
and include values for both attributes: 'genre' and
'format'.public class MovieRecommender {
@Autowired
@MovieQualifier(format=Format.VHS, genre="Action")
private MovieCatalog actionVhsCatalog;
@Autowired
@MovieQualifier(format=Format.VHS, genre="Comedy")
private MovieCatalog comedyVhsCatalog;
@Autowired
@MovieQualifier(format=Format.DVD, genre="Action")
private MovieCatalog actionDvdCatalog;
@Autowired
@MovieQualifier(format=Format.BLURAY, genre="Comedy")
private MovieCatalog comedyBluRayCatalog;
// ...
}Finally, the bean definitions should contain matching qualifier
values. This example also demonstrates that bean
meta attributes may be used instead of the
<qualifier/> sub-elements. If available, the
<qualifier/> and its attributes would take
precedence, but the autowiring mechanism will fallback on the values
provided within the <meta/> tags if no such
qualifier is present (see the last 2 bean definitions below).<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog">
<qualifier type="MovieQualifier">
<attribute key="format" value="VHS"/>
<attribute key="genre" value="Action"/>
</qualifier>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier type="MovieQualifier">
<attribute key="format" value="VHS"/>
<attribute key="genre" value="Comedy"/>
</qualifier>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<meta key="format" value="DVD"/>
<meta key="genre" value="Action"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<meta key="format" value="BLURAY"/>
<meta key="genre" value="Comedy"/>
<!-- inject any dependencies required by this bean -->
</bean>
</beans>CustomAutowireConfigurerThe CustomAutowireConfigurer
is a BeanFactoryPostProcessor that
enables further customization of the autowiring process. Specifically,
it allows you to register your own custom qualifier annotation types
even if they are not themselves annotated with Spring's
@Qualifier annotation.example.CustomQualifier
]]>Note that the particular implementation of
AutowireCandidateResolver that will be
activated for the application context depends upon the Java version. If
running on less than Java 5, the qualifier annotations are not
supported, and therefore autowire candidates are solely determined by
the 'autowire-candidate' value of each bean
definition as well as any
'default-autowire-candidates' pattern(s) available on
the <beans/> element. If running on Java 5 or
greater, the presence of @Qualifier
annotations or any custom annotations registered with the
CustomAutowireConfigurer will also play a
role.Regardless of the Java version, the determination of a "primary"
candidate (when multiple beans qualify as autowire candidates) is the
same: if exactly one bean definition among the candidates has a
'primary' attribute set to 'true',
it will be selected.@ResourceSpring also supports injection using the JSR-250
@Resource annotation on fields or bean
property setter methods. This is a common pattern found in Java EE 5 and
Java 6 (e.g. in JSF 1.2 managed beans or JAX-WS 2.0 endpoints), which
Spring supports for Spring-managed objects as well.@Resource takes a 'name' attribute,
and by default Spring will interpret that value as the bean name to be
injected. In other words, it follows by-name
semantics as demonstrated in this example:public class SimpleMovieLister {
private MovieFinder movieFinder;
@Resource(name="myMovieFinder")
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}If no name is specified explicitly, then the default name will be
derived from the name of the field or setter method: In case of a field,
it will simply be equivalent to the field name; in case of a setter
method, it will be equivalent to the bean property name. So the
following example is going to have the bean with name "movieFinder"
injected into its setter method:public class SimpleMovieLister {
private MovieFinder movieFinder;
@Resource
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}The name provided with the annotation will be resolved as a bean
name by the BeanFactory of which the
CommonAnnotationBeanPostProcessor is aware.
Note that the names may be resolved via JNDI if Spring's SimpleJndiBeanFactory
is configured explicitly. However, it is recommended to rely on the
default behavior and simply use Spring's JNDI lookup capabilities to
preserve the level of indirection.Similar to @Autowired,
@Resource may fall back to standard bean
type matches (i.e. find a primary type match instead of a specific named
bean) as well as resolve well-known "resolvable dependencies": the
BeanFactory interface, the
ApplicationContext interface, the
ResourceLoader interface, the
ApplicationEventPublisher interface and
the MessageSource interface. Note that
this only applies to @Resource usage with
no explicit name specified!So the following example will have its
customerPreferenceDao field looking for a bean with
name "customerPreferenceDao" first, then falling back to a primary type
match for the type CustomerPreferenceDao. The
"context" field will simply be injected based on the known resolvable
dependency type
ApplicationContext.public class MovieRecommender {
@Resource
private CustomerPreferenceDao customerPreferenceDao;
@Resource
private ApplicationContext context;
public MovieRecommender() {
}
// ...
}@PostConstruct and
@PreDestroyThe CommonAnnotationBeanPostProcessor not
only recognizes the @Resource annotation
but also the JSR-250 lifecycle annotations.
Introduced in Spring 2.5, the support for these annotations offers yet
another alternative to those described in the sections on initialization
callbacks and destruction
callbacks. Provided that the
CommonAnnotationBeanPostProcessor is registered
within the Spring ApplicationContext, a
method carrying one of these annotations will be invoked at the same
point in the lifecycle as the corresponding Spring lifecycle interface's
method or explicitly declared callback method. In the example below, the
cache will be pre-populated upon initialization and cleared upon
destruction.public class CachingMovieLister {
@PostConstruct
public void populateMovieCache() {
// populates the movie cache upon initialization...
}
@PreDestroy
public void clearMovieCache() {
// clears the movie cache upon destruction...
}
}For details regarding the effects of combining various lifecycle
mechanisms, see .Classpath scanning for managed componentsThus far most of the examples within this chapter have used XML for
specifying the configuration metadata that produces each
BeanDefinition within the Spring container.
The previous section ()
demonstrated the possibility of providing a considerable amount of the
configuration metadata using source-level annotations. Even in those
examples however, the "base" bean definitions were explicitly defined in
the XML file while the annotations were driving the dependency injection
only. The current section introduces an option for implicitly detecting
the candidate components by scanning the classpath
and matching against filters.@Component and further stereotype
annotationsBeginning with Spring 2.0, the
@Repository annotation was introduced as
a marker for any class that fulfills the role or
stereotype of a repository (a.k.a. Data Access
Object or DAO). Among the possibilities for leveraging such a marker is
the automatic translation of exceptions as described in .Spring 2.5 introduces further stereotype annotations:
@Component,
@Service and
@Controller.
@Component serves as a generic stereotype
for any Spring-managed component; whereas,
@Repository,
@Service, and
@Controller serve as specializations of
@Component for more specific use cases
(e.g., in the persistence, service, and presentation layers,
respectively). What this means is that you can annotate your component
classes with @Component, but by
annotating them with @Repository,
@Service, or
@Controller instead, your classes are
more properly suited for processing by tools or associating with
aspects. For example, these stereotype annotations make ideal targets
for pointcuts. Of course, it is also possible that
@Repository,
@Service, and
@Controller may carry additional
semantics in future releases of the Spring Framework. Thus, if you are
making a decision between using
@Component or
@Service for your service layer,
@Service is clearly the better choice.
Similarly, as stated above, @Repository
is already supported as a marker for automatic exception translation in
your persistence layer.Auto-detecting componentsSpring provides the capability of automatically detecting
'stereotyped' classes and registering corresponding
BeanDefinitions with the
ApplicationContext. For example, the
following two classes are eligible for such autodetection:@Repository
public class JpaMovieFinder implements MovieFinder {
// implementation elided for clarity
}To autodetect these classes and register the corresponding beans
requires the inclusion of the following element in XML where
'basePackage' would be a common parent package for the two classes (or
alternatively a comma-separated list could be specified that included
the parent package of each class).]]>Note that the scanning of classpath packages requires the
presence of corresponding directory entries in the classpath. When
building jars with Ant, make sure to not activate
the files-only switch of the jar task!Furthermore, the
AutowiredAnnotationBeanPostProcessor and
CommonAnnotationBeanPostProcessor are
both included implicitly when using the component-scan element. That
means that the two components are autodetected and
wired together - all without any bean configuration metadata provided in
XML.The registration of those post-processors can be disabled by
including the annotation-config attribute with a
value of 'false'.Using filters to customize scanningBy default, classes annotated with
@Component,
@Repository,
@Service, or
@Controller (or classes annotated with a
custom annotation that itself is annotated with
@Component) are the only detected
candidate components. However it is simple to modify and extend this
behavior by applying custom filters. These can be added as either
include-filter or
exclude-filter sub-elements of the
'component-scan' element. Each filter element
requires the 'type' and
'expression' attributes. Five filtering options exist
as described below.
Filter TypesFilter TypeExample ExpressionDescriptionannotationorg.example.SomeAnnotationAn annotation to be present at the type level in target
components.assignableorg.example.SomeClassA class (or interface) that the target components are
assignable to (extend/implement).aspectjorg.example..*Service+An AspectJ type expression to be matched by the target
components.regexorg\.example\.Default.*A regex expression to be matched by the target
components' class names.customorg.example.MyCustomTypeFilterA custom implementation of the
org.springframework.core.type.TypeFilter
interface.
Find below an example of the XML configuration for ignoring all
@Repository annotations and using "stub"
repositories instead.
]]>It is also possible to disable the default filters by providing
use-default-filters="false" as an attribute of
the <component-scan/> element. This will in effect disable
automatic detection of classes annotated with
@Component,
@Repository,
@Service, or
@Controller.Naming autodetected componentsWhen a component is autodetected as part of the scanning process,
its bean name will be generated by the
BeanNameGenerator strategy known to that
scanner. By default, any Spring 'stereotype' annotation
(@Component,
@Repository,
@Service, and
@Controller) that contains a
name value will thereby provide that name to the
corresponding bean definition. If such an annotation contains no
name value or for any other detected component (such
as those discovered due to custom filters), the default bean name
generator will return the uncapitalized non-qualified class name. For
example, if the following two components were detected, the names would
be 'myMovieLister' and 'movieFinderImpl':@Service("myMovieLister")
public class SimpleMovieLister {
// ...
}@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}If you don't want to rely on the default bean-naming strategy,
you may provide a custom bean-naming strategy. First, implement the
BeanNameGenerator
interface, and be sure to include a default no-arg constructor. Then,
provide the fully-qualified class name when configuring the
scanner:
]]>As a general rule, consider specifying the name with the
annotation whenever other components may be making explicit references
to it. On the other hand, the auto-generated names are adequate whenever
the container is responsible for wiring.Providing a scope for autodetected componentsAs with Spring-managed components in general, the default and by
far most common scope is 'singleton'. However, there are times when
other scopes are needed. Therefore Spring 2.5 introduces a new
@Scope annotation as well. Simply provide
the name of the scope within the annotation, such as:@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}If you would like to provide a custom strategy for scope
resolution rather than relying on the annotation-based approach,
implement the ScopeMetadataResolver
interface, and be sure to include a default no-arg constructor. Then,
provide the fully-qualified class name when configuring the
scanner:
]]>When using certain non-singleton scopes, it may be necessary to
generate proxies for the scoped objects. The reasoning is described in
detail within the section entitled . For this purpose, a
scoped-proxy attribute is available on the
'component-scan' element. The three possible values are: 'no',
'interfaces', and 'targetClass'. For example, the following
configuration will result in standard JDK dynamic proxies:
]]>Providing qualifier metadata with annotationsThe @Qualifier annotation was
introduced in the section above entitled . The examples in that
section demonstrated use of the
@Qualifier annotation as well as custom
qualifier annotations to provide fine-grained control when resolving
autowire candidates. Since those examples were based on XML bean
definitions, the qualifier metadata was provided on the candidate bean
definitions using the 'qualifier' or
'meta' sub-elements of the 'bean'
element in the XML. When relying upon classpath scanning for
autodetection of components, then the qualifier metadata may be provided
with type-level annotations on the candidate class. The following three
examples demonstrate this technique.@Component
@Qualifier("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}@Component
@Genre("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}@Component
@Offline
public class CachingMovieCatalog implements MovieCatalog {
// ...
}As with most of the annotation-based alternatives, keep in mind
that the annotation metadata is bound to the class definition itself,
while the use of XML allows for multiple beans of the same
type to provide variations in their qualifier metadata
since that metadata is provided per-instance rather than
per-class.Defining FactoryBeans with annotationsFactoryBeans can be defined in code using the
@FactoryMethod method level annotation. Factory bean
definiton supports using standard as well as custom qualifiers using
annotations. The scope of the object produces and if it should be a scoped
AOP proxy are determined by the presence of @Scope
and @ScopedProxy annotations. The default scope for
methods with @FactoryMethod can also be inherited
from the class level. The following example shows a variety of usages of the
@FactoryMethod annotation.@Component
public class FactoryMethodComponent {
private static TestBean staticTestBean = new TestBean("staticInstance",1);
@Autowired @Qualifier("public")
public TestBean autowiredTestBean;
private static int i;
@FactoryMethod @Qualifier("static")
public static TestBean staticInstance()
{
return staticTestBean;
}
@FactoryMethod @Qualifier("public")
public TestBean getPublicInstance() {
return new TestBean("publicInstance");
}
@FactoryMethod @BeanAge(1)
protected TestBean getProtectedInstance() {
return new TestBean("protectedInstance", 1);
}
@FactoryMethod @Scope("prototype")
private TestBean getPrivateInstance() {
return new TestBean("privateInstance", i++);
}
@FactoryMethod @Scope("request") @ScopedProxy
private TestBean getPrivateInstance() {
return new TestBean("privateInstance", i++);
}
}
Registering a LoadTimeWeaverThe context namespace introduced in Spring 2.5
provides a load-time-weaver element.
]]>Adding this element to an XML-based Spring configuration file
activates a Spring LoadTimeWeaver for the
ApplicationContext. Any bean within that
ApplicationContext may implement
LoadTimeWeaverAware thereby receiving a
reference to the load-time weaver instance. This is particularly useful in
combination with Spring's JPA support where
load-time weaving may be necessary for JPA class transformation. Consult
the LocalContainerEntityManagerFactoryBean Javadoc
for more detail. For more on AspectJ load-time weaving, see .