A bean definition is essentially a set of rules for creating one or more objects. In response to a request, the container looks up the named bean's rule set and uses the configuration metadata contained in that bean's definition to create (or retrieve) the actual object.
If you use XML-based configuration metadata, you specify the type
( or class) of the object to be instantiated, in the class
attribute of the <bean/>
element. This class
attribute (which is internally the Class
property of the BeanDefinition
instance) is typically required. The Class
property can be used in one of two ways:
Typically, to specify the class of the bean that should be built if the container itself directly creates the bean by reflectively calling its constructor, which is somewhat equivalent to Java code with the
new
operator.To specify the actual class containing the
static
is a factory method that is called to create an object, in the less common case where the container calls astatic
factory method on the class to create the bean. The object type returned from a call to astatic
factory method can be the same class or a completely different class.
Creating an instance using a constructor
If the bean is instantiated using a constructor, all standard classes can be used and will be compatible with Spring. That is, the class being developed does not have to implement any specific interfaces or be written in a specific way. Simply setting the bean class should be sufficient. However, depending on what type of IoC is used for that particular bean, a default (empty) constructor may be needed.
Spring's IoC container can manage almost any class you need to manage. It is not limited to managing true JavaBeans. Most Spring users prefer actual JavaBeans using a default (no-argument) constructor and appropriate setters and getters modeled after container properties. Your container may also contain more exotic non-bean-style classes. If, for example, you want to use a legacy connection pool that is completely inconsistent with the JavaBean specification, Spring can manage that too.
Using XML-based configuration metadata, you can define your bean class like this:
<bean id="exampleBean" class=" examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
More details about the mechanism for providing arguments to the constructor (if required) and setting properties object instance after the object is constructed, see Dependency Injection.
Creating an instance using a static factory method
When defining a bean that you instantiate using a static
factory method, use the class
attribute to specify the class that contains the static
code> factory method, and the factory-method
attribute to set the name of the factory method itself.
You should be able to call this method (with optional arguments, as described below) and return a runnable object,
which will then be treated as if it had been created using the constructor. One use case for such a bean definition
is to call static
factories in legacy code.
The following bean definition specifies that the
bean will be created by calling a factory method. The definition does not specify the type (class) of the returned
object, but only the class containing the factory method. In this example, the createInstance()
method
must be static
. The following example shows how to set a factory method:
<bean id="clientService"
class="examples.ClientService"
factory-method="createInstance"/>
In the following The example shows a class that will work with the previous bean definition:
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
class ClientService private constructor() {
companion object {
private val clientService = ClientService()
@JvmStatic
fun createInstance() = clientService
}
}
Learn more about the mechanism for providing (optional) arguments to a factory method and setting the properties of an object instance after the object is returned from the factory.
Creating an instance using an instance factory method
Similar to creating an instance through a static factory method, creating an instance using an instance factory
method calls a non-static method of an existing bean in the container to create a new bean. To use this
mechanism, leave the class
attribute empty, and in the factory-bean
attribute specify
the name of the bean in the current (or parent or predecessor) container that contains the instance method that
will be called to create the object. Set the name of the factory method itself using the
factory-method
attribute. The following example shows how to configure such a bean:
<!-- a factory bean containing the createInstance() method -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- bean that will be created using the factory bean -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
The following example shows the corresponding class :
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}
class DefaultServiceLocator {
companion object {
private val clientService = ClientServiceImpl()
}
fun createClientServiceInstance(): ClientService {
return clientService
}
}
One factory class can contain more than one factory method, as shown in the following example:
<bean id="serviceLocator" class="examples. DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
<bean id="accountService"
factory-bean="serviceLocator"
factory-method="createAccountServiceInstance"/>
The following example shows the corresponding class :
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private static AccountService accountService = new AccountServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
public AccountService createAccountServiceInstance() {
return accountService;
}
}
class DefaultServiceLocator {
companion object {
private val clientService = ClientServiceImpl()
private val accountService = AccountServiceImpl()
}
fun createClientServiceInstance(): ClientService {
return clientService
}
fun createAccountServiceInstance(): AccountService {
return accountService
}
}
This approach demonstrates that A factory bean can be managed and configured using dependency injection (DI). See Dependencies and configuration details.
FactoryBean
(note the capitalization) refers to the Spring-specific implementation class FactoryBean
.
Determining the type of a bean at runtime
Determining the type of a particular bean at runtime is a non-trivial task. The specified class in a bean's
metadata definition is simply the original reference to a class, potentially combined with a declared factory
method or being a FactoryBean
class, which could result in a different bean type at runtime, or not
specified at all in the case instance-level factory method (which is resolved instead through the given name
factory-bean
). Additionally, AOP proxying can place a bean instance in an interface-based proxy
with limited discovery of the actual type of the target bean (only its implemented interfaces).
The recommended way to find out the actual runtime type of a particular bean is to call
BeanFactory.getType
for the given bean name. This takes into account all the above cases and
returns the object type that would be returned by calling BeanFactory.getBean
for the same bean
name.