In 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.
The
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
As 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.
![]() | Note |
---|---|
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 Section 4.11, “Annotation-based configuration” |
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 Section 4.8.5, “Convenient ApplicationContext
instantiation for web applications”).
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.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <!-- more bean definitions go here --> </beans>
Instantiating 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;
It 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:
<beans> <import resource="services.xml"/> <import resource="resources/messageSource.xml"/> <import resource="/resources/themeSource.xml"/> <bean id="bean1" class="..."/> <bean id="bean2" class="..."/> </beans>
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.
![]() | Note |
---|---|
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. |
A 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.
Table 4.1. The bean definition
Feature | Explained in... |
---|---|
class | |
name | |
scope | |
constructor arguments | |
properties | |
autowiring mode | |
dependency checking mode | |
lazy-initialization mode | |
initialization method | |
destruction method |
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.)
Every bean has one or more id
s (also called
identifiers, or names; these terms refer to the same thing). These
id
s 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 id
s,
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).
In 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.
<alias name="fromName" alias="toName"/>
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:
<alias name="componentA-dataSource" alias="componentB-dataSource"/> <alias name="componentA-dataSource" alias="myApp-dataSource" />
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.
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 the section called “Instantiation using an instance factory method” and Section 4.6, “Bean definition inheritance” 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).
When 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:
<bean id="exampleBean" class="examples.ExampleBean"/> <bean name="anotherExample" class="examples.ExampleBeanTwo"/>
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.
When 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.
<bean id="exampleBean" class="examples.ExampleBean2" factory-method="createInstance"/>
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.
In 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.
![]() | Note |
---|---|
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
|
A 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:
Resource res = new FileSystemResource("beans.xml"); BeanFactory factory = new XmlBeanFactory(res);
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.