This article discusses how to extend the bean functionality in spring in the spring life cycle.
Expansion of the container
In general, developers do not need to inherit ApplicationContext
to implement their own subclass extension functionality. But the spring IOC container can actually add some functionality by implementing an interface. These interfaces are described below.
Pass
BeanPostProcessor
Defining beans
BeanPostProcessor
Interfaces define callback methods that developers can use to instantiate their own logic, rely on parsing logic, and so on. If the developer just wants to do something in the spring container after the instantiation, configuration and initialization of the bean, it can be done by using it BeanPostProcessor
.
Developers can configure multiple BeanPostProcessor
instances, and developers can specify the order in which they are executed by configuring the order
properties BeanPostProcessor
. Of course, you must implement the interface at the same time to configure the order Ordered
. If developers write their own BeanPostProcessor
, developers should consider implementing the interface at the same time Ordered
. If you want to know more information, you can refer to BeanPostProcessor
Ordered
the Javadoc of the interface.
BeanPostProcessors
is to manipulate the bean instance, in other words, the Spring IOC container must first initialize the bean before it BeanPostProcessors
begins to work.
BeanPostProcessors
the scope of the action is container-based. Of course, it is only when developers use the hierarchy of containers that they need to be considered. If the developer defines one in the container BeanPostProcessor
, the instance will only handle the operation after the bean is initialized in the container in which it resides. In other words, a bean in one container is not BeanPostProcessor
subsequently processed after initialization, as defined in another container, even if two containers belong to the same container.
org.springframework.beans.factory.config.BeanPostProcessor
The interface consists of 2 callback methods. When an instance of this interface is registered with a container, for each instance created by the container, the post processor gets a call to the callback before the container begins to initialize. The post processor can take any action against the bean instance, including completely ignoring the callback function. The Bean's post processor usually checks the callback interface or wraps the bean with a proxy. Some of the underlying classes, such as the spring AOP Proxy, are implemented by subsequent processors of the bean.
ApplicationContext
The configured beans are automatically checked for implementation of the Beanpostprocessor interface, which ApplicationContext
registers the beans as subsequent processors, so that the subsequent processors are called after the Bean is created. The subsequent processor of the bean is managed by the container just like any other bean.
It should be noted that when using annotations on the factory method of the configuration class @Bean
, the return value of the factory method should be the implementation class itself, or at least the org.springframework.beans.factory.config.BeanPostProcessor
interface, to make it clear that the bean is a post processor. Otherwise, ApplicationContext
it is not possible to automatically create this bean when it belongs to the back processor. Because a bean successor processor is required to process the other beans in the container sequentially, the type needs to be checked as early as possible.
Although the spring team recommends a follow-up process for registering beans through ApplicationContext
automatic checking, spring also supports programmatic way of passing addBeanPostProcessor
methods. This can be useful sometimes, especially if you need to perform some conditional judgment before registering, or when you copy a Bean's successor processor in a structured context. It is important to note that programming is done by BeanPostProcessors
ignoring the Ordered
interface: The programming registration is BeanPostProcessors
always performed before the automatic check-out BeanPostProcessors
, and the explicit order definition is ignored.
The container treats those classes that implement the BeanPostProcessor
interface in particular. All BeanPostProcessors
and the beans they reference are initialized directly at startup as ApplicationContext
a special phase of startup. Then, all the BeanPostProcessors
beans that are registered and applied sequentially to the container. Because an AOP automatic proxy is BeanPostProcessor
implemented by, either BeanPostProcessor
it or itself is not an Bean
automatic proxy, nor is it injected into the bean. For such a bean, the developer should be aware of the log information similar to info Bean不适合由所有的BeanPostProcessor接口处理
.
It is important to note that once the developer is BeanPostProcessor
using automatic loading or @Resource
loading the bean,spring may enter undesirable beans through type matching, so that these beans cannot be automatically proxied or subsequently processed. For example, if a developer's bean has an annotated @Resource
dependency injection instead of a dependency injection directly through the name attribute, spring will find a matching dependency by type matching.
The following example describes how to write, register, and use BeanPostProcessors
.
Example: Hello World
BeanPostProcessor
Way
The first example illustrates the basic usage. BeanPostProcessor
the custom implementation, shown in the example, invokes the toString()
method and prints to the console after the bean is created.
Refer to the following code:
PackageScriptingImportOrg.springframework.beans.factory.config.BeanPostProcessor;ImportOrg.springframework.beans.BeansException; Public class instantiationtracingbeanpostprocessor implements beanpostprocessor { //Simply return the instantiated bean As-is PublicObjectpostprocessbeforeinitialization(Object Bean, String beanname)throwsbeansexception {returnBean//We could potentially return any object reference here ...} PublicObjectpostprocessafterinitialization(Object Bean, String beanname)throwsbeansexception {System.out.println ("Bean" "+ Beanname +"' Created:"+ bean.tostring ());returnBean }}
<?xml version= "1.0" encoding= "UTF-8"?><beans xmlns =< Span class= "Hljs-value" > "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.xsd http://www . Springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.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) was instantiated, this custom beanpostprocessor implementation would OUTP UT the fact to the system console -- <Bean class="scripting." Instantiationtracingbeanpostprocessor "/></Beans>
As you can see from the configuration of XML, it InstantiationTracingBeanPostProcessor
is simply defined as a bean. It doesn't even have a name, but it's a bean, so you can still do dependency injection.
The following Java application executes the preceding code and configuration:
ImportOrg.springframework.context.ApplicationContext;ImportOrg.springframework.context.support.ClassPathXmlApplicationContext;ImportOrg.springframework.scripting.Messenger; Public Final class Boot { Public Static void Main(FinalString[] args)throwsException {ApplicationContext CTX =NewClasspathxmlapplicationcontext ("Scripting/beans.xml"); Messenger Messenger = (Messenger) Ctx.getbean ("Messenger"); System.out.println (Messenger); }}
The output will look similar to the following:
Bean‘messenger‘: org.springframework.scripting.groovy.GroovyMessenger@272961org.springframework.scripting.groovy.GroovyMessenger@272961
Example:
RequiredAnnotationBeanPostProcessor
Using callback interfaces or annotations and BeanPostProcessor
implementations is common to extend the way of the spring IOC container. One example in spring is the RequiredAnnotationBeanPostProcessor
fact that the attribute that is used to ensure that the javabean tag is actually injected into the dependency.
Pass
BeanFactoryPostProcessor
Defining Configuration Metadata
The next extension is org.springframework.beans.factory.config.BeanFactoryPostProcessor
. Semantically, this interface is somewhat similar BeanPostProcessor
, but there is a big difference: the BeanFactoryPostProcessor
operation Bean Configuration metadata , that is, Spring allows BeanFactoryPostProcessor
to read the configuration source data, It is possible to change the configuration metadata before the container instance initializes the session bean.
As mentioned earlier, developers can configure multiple BeanFactoryPostProcessors
, and developers can control the order in which they are executed. Of course, the configuration order is an interface that must be implemented Ordered
. If you implement your own BeanFactoryPostProcessor
, developers should also consider implementing Ordered
interfaces. You can BeanFactoryPostProcessor
refer Ordered
to the Javadoc of the interface to learn more details.
If the developer wants to change the actual bean instance (such as the object created by the configuration metadata), then you need to use it BeanPostProcessor
. However, it BeanPostProcessor
is possible BeanFactoryPostProcessor
to work cooperatively with the bean instance in a technical way (for example, by using a BeanFactory.getBean()
function), which causes some immature bean initialization problems and destroys the Standard Life cycle of the container standard. This behavior can lead to negative behavior, such as bypassing the bean's subsequent processing process, and so on. At the same time, the BeanFactoryPostProcessors
scope of the action is container-based. Of course it is only relevant when using the container hierarchy. If a developer defines one in a container BeanFactoryPostProcessor
, its configuration is only applied to that configured container. The bean definition in another container will not be BeanFactoryPostProcessors
processed by subsequent processing, even if two containers are part of the same hierarchy.
When ApplicationContext
a subsequent processor is declared in, the subsequent processor of the bean is executed automatically to implement the behavior defined in the configuration. Spring includes a number of pre-defined, well-followed processors that can be used, such as PropertyOverrideConfigurer
and PropertyPlaceholderCOnfigurer
, to BeanFactoryPostProcessor
register custom property editors with custom, for example.
ApplicationContext
The bean that implements the interface in the container is automatically checked BeanFactoryPostProcessor
. It is then used as a subsequent processor in the factory when appropriate. Developers can deploy subsequent processors like other beans.
If you use Beanpostprocessor, developers typically do not configure beanfactorypostprocessors to delay initialization. Because if there is no other bean reference Bean(Factory)PostProcessor
, then the subsequent processor will not initialize the instance at all. Therefore, delaying the initialization of the configuration will be ignored by spring, and Bean(Factory)PostProcessor
will be instantiated regardless of whether the configuration deferred initialization, even if the <beans />
default-lazy-init
property is configured as true
.
Example: Class name substitution
BeanFactoryPostProcessor
Developers use it PropertyPlaceholderConfigurer
to Properties
materialize the value of a property from a different file using the standard Java format. This class allows developers to deploy applications to different environments using different attributes, such as database URLs
or user name passwords, without the need to modify the XML definition.
Refer to the following XML configuration, using DataSource
placeholders to define some of the configuration of the database. This example also shows that the configured properties are configured with additional Properties
files. At run time, PropertyPlaceholderConfigurer
some of the properties that are applied to the metadata will be replaced DataSource
. The replacement value, which is the name of the placeholder, is based on the Ant/log4j/JSP EL
form of the property configuration.
<beanclass="Org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> < Property name="Locations"Value="Classpath:com/foo/jdbc.properties"/></bean><beanID="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 placeholder value is configured in another file, using the Java Properties
format, as follows:
jdbc.driverClassName=org.hsqldb.jdbcDriverjdbc.url=jdbc:hsqldb:hsql://production:9002jdbc.username=sajdbc.password=root
As a result, strings are ${jdbc.username}
replaced at run time sa
, and other placeholders are replaced in turn. The PropertyPlaceholderConfigurer
placeholder is checked in the bean definition, and the prefix suffix of the placeholder can be customized.
After Spring 2.5, a context
namespace is introduced, and a dedicated configuration element can be used to configure the property placeholder. Multiple addresses can use a comma delimiter.
<context:property-placeholder location="classpath:com/foo/jdbc.properties"/>
PropertyPlaceholderConfigurer
Not only the files specified by the developer are viewed Properties
. By default, it will still check the Java configuration if it cannot find the attribute in the specified property file System
. Developers can systemPropertiesMode
modify this behavior by configuring the property, which has the following three values:
- Nerver (0): Never Check System Properties
- Fallback (1): If the system property is checked when a specific property is not found from the specified property file, this is the default value.
- Override (2): First look up system properties before trying to check the specified configuration file. The properties of the system override the properties of the specified file.
You can check out PropertyPlaceholderConfigurer
the Javadocs to get more information.
Developers can use PropertyPlaceholderConfigurer
alternative class names, which is useful when a particular implementation class needs to be modified.
<Bean class=" Org.springframework.beans.factory.config.PropertyPlaceholderConfigurer "> < property name="Locations"> <value>Classpath:com/foo/strategy.properties</value> </Property > < property name="Properties"> <value>Custom.strategy.class=com.foo.defaultstrategy</value> </Property ></Bean><bean id="Servicestrategy" class="${custom.strategy.class}" />
If a class cannot be parsed at run time, it will fail when the bean instance is created.
Example:
PropertyOverrideConfigurer
PropertyOverrideConfigurer
, is another bean's post processor, some similar PropertyPlaceholderConfigurer
, but different from the latter, the original definition may have a default value, or there is no value. If the overwritten Properties
file does not have an exact bean attribute, the default definition is used.
It is important to note that the bean definition itself is not known to be overwritten, so it is difficult to visualize the configuration being overwritten from the definition of XML. If multiple instances are configured with PropertyOverrideConfigurer
different values defined, the last configuration will take effect based on the override mechanism.
The configuration of the properties file is similar to the following:
beanName.property=value
Like what:
dataSource.driverClassName=com.mysql.jdbc.DriverdataSource.url=jdbc:mysql:mydb
The above instance file, which can be used for a bean named DataSource, contains the properties of the driver and the URL.
The composite accessory name is also supported, but requires that the components on each path need to be non-null, such as:
foo.fred.bob.sammy=123
The specified overridden value is always literal, and cannot be another bean dependency, and this Convention is applied to the case where the original value refers specifically to the bean reference.
In the namespaces introduced in Spring 2.5 context
, you can also specify that the configuration overrides the file attributes as follows:
<context:property-override location="classpath:override.properties"/>
Custom
FactoryBean
The initialization logic
Some objects themselves are similar to factories that can be considered to implement org.springframework.beans.factory.FactoryBean
interfaces.
FactoryBean
An interface is a plug-in logic similar to a spring IOC container. If the developer's code has complex initialization code and the Java code in the configuration is more efficient than XML, developers can consider creating their own FacotoryBean
objects, putting complex initialization operations into the class, and extending the customizations FactoryBean
to the container.
FacotryBean
The interface provides the following three methods:
Object getObject()
: Returns an object created by a factory. Instances can be shared, depending on whether the scope of the returned Bean is a prototype or a singleton.
boolean isSingleton()
: If a singleton is returned, the FactoryBean
True
False
Class getObjectType()
: Returns getObject()
the type of the object returned by the method, or null if the object type is unknown.
FactoryBean
The concepts and interfaces are widely used in the pre-spring framework, and spring itself has more than 50 FactoryBean
implementations.
When a developer needs an FactoryBean
instance instead of the bean it produces, the method that is called is preceded by a ApplicationContext
getBean()
symbol before its ID &
. That is, for a given FactoryBean
, whose ID is called, the call returns the myBean
getBean("myBean")
Bean Object It produces, and the call getBean("&myBean")
returns the FactoryBean
instance itself.
Spring Core Technology IOC container (vii)