This article mainly summarizes some callback methods and extensible points provided by Spring container before and after initializing the instance. Using these methods and extension points, some special logical processing can be done before and after Spring initialization instances.
The following is mainly introduced:
Class-level life cycle initialization callback method init-method configuration, InitializingBean interface and PostConstruct annotation
Container-level extension BeanPostProcessor interface and BeanFactoryPostProcessor interface
1. Class-level life cycle callback
1.1init-method
Reference: Springbeanxsdinit-method
init-method is a configuration item when declaring a bean in the Spring configuration file. The value of the init-method configuration item is a parameterless method in the class, but an exception can be thrown. This method will be called after the Spring container instantiates the object and sets the property value.
The functions that can be implemented by init-method are consistent with the InitializingBean interface and PostConstruct annotation
Spring configuration files and test classes are as follows:
<bean id = "initMethodBeanService" init-method="init"> <property name="f2" value="2"/></bean>
The test class is as follows:
public class InitMethodBeanService {private static Integer f1;private Integer f2;static {f1 = 1;System.out.println("InitMethodBeanService static block execute...");}public InitMethodBeanService(){System.out.println("InitMethodBeanService construct method execute...");}public void init(){System.out.println("InitMethodBeanService init method execute...");}public Integer getF2() {return f2;}public void setF2(Integer f2) {this.f2 = f2;System.out.println("InitMethodBeanService setF2 method execute...");}}The execution results are printed as follows:
InitMethodBeanService static block execute...InitMethodBeanService construct method execute...InitMethodBeanService setF2 method execute...InitMethodBeanService init method execute...test method execute...
1.2InitializingBean interface
Reference: Spring official document beans-factory-lifecycle-initializingbean
An InitializingBean interface declares a method afterPropertiesSet, which is called after the Spring container instantiates the object and sets the property value. It is consistent with the functionality implemented above init-method, so Spring does not recommend using the InitializingBean interface.
The example is relatively simple, not listed
1.3PostConstruct annotation
Translation: Spring official document beans-postconstruct-and-predestroy-annotations
@PostConstruct annotation is a life cycle callback method that is consistent with the implementation of the init-method and InitializingBean interfaces.
@PostConstructpublic void postConstruct(){ System.out.println("PostConstructService postConstruct method execute...");}Summarize the above three life cycle callback methods init-method, InitializingBean interface, @PostConstruct annotation
1. All are instantiated and post-processed for single classes
2. The execution time is called after class instantiation and member variables are injected.
3. For init-method, you can also configure the default initialization method under the beans element of the Spring configuration file, and the configuration item is default-init-method
4. If the initialization methods configured in the above three methods are different, the execution order is: @PostConstruct annotation method>InitializingBean's afterPropertiesSet>init-method method; if the methods configured in the three methods are the same, the method will be executed only once (refer to: Spring official document beans-factory-lifecycle-combined-effect)
5. There is an initial callback method, and there are also a destroyed callback method. @PostConstruct annotation method>InitializingBean's afterPropertiesSet>init-method methods correspond to @PreDestroy annotation method>DisposableBean's destroy>destroy-method method
2. Container level extension
Translation: Spring official document 3.8ContainerExtensionPoints
Generally speaking, developers do not need to customize a subclass of ApplicationContext to extend SpringIOC containers. SpringIOC containers can achieve the extension of SpringIOC containers through some exposed interfaces.
2.1BeanPostProcessor interface
2.1.1bean instance initialization of postprocessor and postprocessor chain
The BeanPostProcessor interface defines two container-level callback methods postProcessBeforeInitialization and postProcessAfterInitialization, which are used for some logical processing after initializing the instance and will be processed for all instances in the container. The class that implements the BeanPostProcessor interface is called the bean instance initialization postprocessor.
If multiple instance initialization postprocessors are integrated into SpringIOC containers, the set of these postprocessors is called bean instance initialization postprocessor chain.
The postProcessBeforeInitialization method is executed after class instantiation and member variable injection is completed, and before the initialization method (such as InitializingBean's afterPropertiesSet method)
The postProcessAfterInitialization method is executed after class instantiation and member variable injection is completed, and the initialization method (such as InitializingBean's afterPropertiesSet method) is executed after
Summarize:
1. The instance initialization post-processor is mostly used for some proxy operations on the instance. Some features that use AOP in Spring are also implemented through post-processors.
2. The instance initialization post-processor chain is multiple post-processors, and there will be problems with the execution order. You can implement the Ordered interface to specify the execution order of post-processing. The Ordered interface declares the getOrder method. The smaller the return value of the method, the higher the priority of post-processing and the earlier execution.
3. When initializing the postprocessor by implementing the BeanPostProcessor interface, it is recommended to implement the Ordered interface and specify priority.
4. The scope of these postprocessors is the current SpringIOC container, that is, the SpringIOC container that the postprocessor is declared. For SpringIOC containers with hierarchical structures, the processor chain after instance initialization does not act on the instance initialized by other containers, even if the two containers are on the same hierarchy.
5. The implementation class of the instance initialization post-processor only needs to be declared the same as the ordinary Spring-managed beans. The SpringIOC container will automatically detect it and add it to the instance initialization post-processor chain.
6. Compared with automatic detection, we can also call the addBeanPostProcessor method of ConfigurableBeanFactory to programmatically add an instance initialization postprocessor to the instance initialization postprocessor chain. This is more practical in scenarios where adding conditions need to be determined. This programming approach ignores the order specified by the implemented Ordered interface, but will act on all instances that are automatically detected before the initialization of the post-processor.
2.1.2 Bean instance initialization postprocessor and AOP
BeanPostProcessor is a special interface, and the class implementing this interface will be used as a postprocessor for instances of Spring-managed beans. Therefore, in a special stage of Spring application context startup, all instances that implement the BeanPostProcessor interface will be directly initialized, and the classes referenced by the instance will also be instantiated. Then as a postprocessor to apply to other normal instances.
Since AOP's automatic proxy is implemented in the form of instantiating postprocessors, neither the bean instance initializes the postprocessor chain instance or its referenced instance can be automatically proxyed. Therefore, do not weave in the face on these examples. (For these instances, a log message will be generated: "Class foo cannot be processed by all instantiated postprocessor chains, i.e. cannot be automatically proxyed").
Note: When the instantiation postprocessor refers to other beans in the form of autowiring or @Resource, the Spring container may inject non-specified beans when it is injected with type matching dependency (for example, the instantiation postprocessor implementation class depends on beans in the form of Resource. If the set method is consistent with the name of the dependent bean or the dependent bean does not declare the name, the dependency injection will be injected in the form of type matching, and a non-specified bean may be injected at this time). This can also cause automatic proxying or other methods of instantiation postprocessor processing to fail.
2.1.3 Bean instance initialization postprocessor example
public class BeanPostProcessorService implements BeanPostProcessor {@Override public Object postProcessAfterInitialization(Object o, String s) throws BeansException {System.out.println("BeanPostProcessorService postProcessAfterInitialization method execute...");return o;}@Override public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {System.out.println("BeanPostProcessorService postProcessBeforeInitialization method execute...");return o;}}2.2BeanFactoryPostProcessor interface
2.2.1 beanfactory postprocessor
By implementing the BeanFactoryPostProcessor interface, you can read the configuration metadata of beans managed by the container and make changes before the bean is instantiated. These beans are called beanfactory postprocessors.
Similarities and differences between BeanFactoryPostProcessors and BeanPostProcessor interfaces:
Similarities:
All are container-level postprocessors
All can be configured with multiple postprocessors, and the execution order is specified by implementing the Ordered interface.
They are processed for beans managed in containers declared by interfaces. In containers with hierarchical structures, beans in other containers cannot be processed, even if the two containers are at the same level.
All of them only need to be declared in the container like ordinary beans. The container will automatically detect and register as a postprocessor.
Delay initialization property configuration will be ignored
Differences:
The BeanFactoryPostProcessors interface processes the configuration metadata of the bean before instantiation of beans, and the BeanPostProcessor interface processes the instance of the bean after instantiation of beans**
The BeanFactoryPostProcessors interface can also obtain an instance of a bean through the BeanFactory.getBean() method, which will cause the bean to be instantiated. Since the BeanFactoryPostProcessors postprocessor is executed before all beans are instantiated, the BeanFactory.getBean() method will cause the bean to be instantiated in advance, thus breaking the life cycle of the container standard, which may cause some negative impacts (for example, the bean instantiated in advance will ignore the processing of the bean instantiated postprocessor).
2.2.2 Spring built-in and custom beanfactory postprocessor
Spring has built-in beanfactory postprocessors (for example: PropertyPlaceholderConfigurer and PropertyOverrideConfigurer). It also supports the implementation of the BeanFactoryPostProcessor interface and customizes the beanfactory postprocessor. Let’s talk about Spring’s built-in postprocessors and custom postprocessors.
PropertyPlaceholderConfigurer
In order to avoid the risks caused by modification of the main XML definition file, Spring provides configuration separation, and can configure some variables that may be changed into the property configuration file and reference it in the XML definition file as a placeholder. In this way, modifying the configuration only requires modifying the attribute configuration file. PropertyPlaceholderConfigurer is used to detect placeholders and replace placeholders with configuration property values. Examples are as follows:
PropertyPlaceholderConfigurer uses the jdbc.properties property configuration file to replace the property placeholder for database-related information in the dataSource bean with the corresponding configuration value at runtime.
The XML configuration is as follows:
<bean> <property name="locations" value="classpath:com/foo/jdbc.properties"/></bean><bean id="dataSource" destroy-method="close" > <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/>The attribute configuration file jdbc.properties is as follows:
jdbc.driverClassName=org.hsqldb.jdbcDriverjdbc.url=jdbc:hsqldb:hsql://production:9002jdbc.username=sajdbc.password=root
PropertyPlaceholderConfigurer not only supports reading of property configuration files, but also supports reading of system properties. Read priority can be configured through the systemPropertiesMode property value. The various values are described as follows:
0: Do not read system properties
1: If the configuration for the corresponding placeholder is not retrieved in the referenced attribute configuration file, the system attribute is read. Default is 1
2: Read the system attributes first, and then read the referenced attribute configuration file. This configuration may cause system properties to overwrite the configuration file.
PropertyOverrideConfigurer
The PropertyOverrideConfigurer class can directly assign values to beans in the container by referring to the property configuration file. When a bean's property is assigned by multiple PropertyOverrideConfigurer class instances, the last value overrides the previous one.
Assigning the above dataSource bean as an example:
The PropertyOverrideConfigurer class uses a new way to reference the property configuration file, as follows:
<context:property-override location="classpath:override.properties"/>
The naming rules of properties of override.properties property configuration file are different from those above (in the above example, it is necessary to ensure that the property name and placeholder are consistent), and the naming rules are beanName.property
dataSource.driverClassName=com.mysql.jdbc.DriverdataSource.url=jdbc:mysql:mydbdataSource.username=sadataSource.password=root
Supports assignment of composite attributes, but ensures that the object that references the assigned attribute is not empty, for example: foo.fred.bob.sammy=123
Custom bean factory postprocessor
The custom bean factory postprocessor implements the BeanFactoryPostProcessor interface to complete the modification of the configuration metadata of the bean managed by Spring container. For example: modify the value injected by class attributes, the example is as follows:
Define a user class UserBean
public class UserBean {private String userName;public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}}Spring XML configuration file configures user class and injects the value haha to the username attribute userName
<bean/><bean id="user"> <property name="userName" value="haha"/></bean>
Below is a custom bean factory postprocessor, modify the value of the property userName to heihei
public class BeanFactoryPostProcessorService implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("BeanFactoryPostProcessorService postProcessBeanFactory method execute..."); BeanDefinition bd = beanFactory.getBeanDefinition("user"); MutablePropertyValues pv = bd.getPropertyValues(); if(pv.contains("userName")) { pv.addPropertyValue("userName", "heihei"); } }}Summarize
The above is all the detailed explanation of Spring life cycle callbacks and container extensions in this article. I hope it will be helpful to everyone. Interested friends can continue to refer to this site:
A brief discussion on the application of custom annotations in Spring
Spring's IOC code analysis
SpringMVC Interceptor HandlerInterceptor Usage Code Example
If there are any shortcomings, please leave a message to point it out. Thank you friends for your support for this site!