Home >Web Front-end >JS Tutorial >Detailed explanation of Spring life cycle and container extension usage
This time I will bring you a detailed explanation of the use of Springlife cycle and container extensions. What are the precautions for the use of Spring life cycle and container extensions? The following are practical cases. , let’s take a look.
The following is the main introduction:
Class-level life cycle initialization callback method init-method configuration, InitializingBean interface and PostConstruct annotation
Container-level extended 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 it can throw an exception. This method will be called after the Spring container instantiates the object and sets the property values.
The functions that init-method can implement are consistent with the InitializingBean interface and PostConstruct annotations
Spring configuration files and test classes are as follows:
<bean id = "initMethodBeanService" class="name.liuxi.spring.ext.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 result is 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
The InitializingBean interface declares a method afterPropertiesSet, which will be called after the Spring container instantiates the object and sets the property values. The function implemented by the init-method above is consistent, so Spring does not recommend using the InitializingBean interface.
The example is relatively simple and will not be listed
1.3PostConstruct annotations
Translation: Spring official documentation beans-postconstruct-and-predestroy-annotations
The @PostConstruct annotation is a life cycle callback method that has the same effect as the init-method and InitializingBean interfaces
@PostConstruct public void postConstruct(){ System.out.println("PostConstructService postConstruct method execute..."); }
Summarize the above three life cycle callback methods init-method, InitializingBean interface, and @PostConstruct annotation
1. They are all for post-instantiation processing of a single class
2. The execution time is called after the class instantiation is completed and the 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. The configuration item is default-init-method
4. If the initialization methods configured in the above three ways are different, the execution order is: @PostConstruct annotation method–>InitializingBean’s afterPropertiesSet–>init-method method; if the methods configured in the three ways are the same, the methods are only Execute once (refer to: Spring official document beans-factory-lifecycle-combined-effect)
5. There is an initialization callback method, and there is also a corresponding destruction callback method. The @PostConstruct annotation method–>InitializingBean’s afterPropertiesSet–>init-method method corresponds to the @PreDestroy annotation method–>DisposableBean’s destroy–>destroy-method method
2. Container level extension
Translation: Spring official document 3.8ContainerExtensionPoints
Under normal circumstances, developers do not need to customize a subclass of ApplicationContext to extend the SpringIOC container. The SpringIOC container can extend the SpringIOC container through some externally exposed interfaces.
2.1BeanPostProcessor interface
2.1.1Bean instance initialization post-processor and post-processor 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 post-processor.
If multiple instance initialization post-processors are integrated in the SpringIOC container, the collection of these post-processors is called a bean instance initialization post-processor chain.
postProcessBeforeInitialization方法在类实例化且成员变量注入完成之后执行,初始化方法(例如InitializingBean的afterPropertiesSet方法)之前执行
postProcessAfterInitialization方法在类实例化且成员变量注入完成之后执行,初始化方法(例如InitializingBean的afterPropertiesSet方法)之后执行
总结:
1.实例初始化后处理器多用于对实例的一些代理操作。Spring中一些使用到AOP的特性也是通过后处理器的方式实现的。
2.实例初始化后处理器链是多个后处理器,就会有执行顺序的问题,可以通过实现Ordered接口,指定后处理的执行顺序,Ordered接口声明了getOrder方法,方法返回值越小,后处理的优先级越高,越早执行。
3.在通过实现BeanPostProcessor接口自定义实例初始化后处理器的时候,建议也实现Ordered接口,指定优先级。
4.这些后处理器的作用域是当前的SpringIOC容器,即后处理器被声明的SpringIOC容器。对于有层次结构的SpringIOC容器,实例初始化后处理器链不会作用于其他容器所初始化的实例上,即使两个容器在同一层次结构上。
5.实例初始化后处理器的实现类只需要和普通的被Spring管理的bean一样声明,SpringIOC容器就会自动检测到,并添加到实例初始化后处理器链中。
6.相对于自动检测,我们也可以调用ConfigurableBeanFactory的addBeanPostProcessor方法,以编程的方式将一个实例初始化后处理器添加到实例初始化后处理器链中。这在需要判定添加条件的场景下比较实用。这种编程式的方式会忽略到实现的Ordered接口所指定的顺序,而会作用于所有的被自动检测的实例初始化后处理器之前。
2.1.2bean实例初始化后处理器与AOP
BeanPostProcessor是一个特殊的接口,实现这个接口的类会被作为Spring管理的bean的实例的后处理器。因此,在Spring应用上下文启动的一个特殊阶段,会直接初始化所有实现了BeanPostProcessor接口的实例,以及该实例所引用的类也会被实例化。然后作为后处理器应用于其他普通实例。
由于AOP的自动代理是以实例化后处理器的方式实现的,所以无论是bean实例初始化后处理器链实例还是其引用的实例,都不能被自动代理。因而,不要在这些实例上进行切面织入。(对于这些实例,会产生这样的日志消息:“类foo不能被所有的实例化后处理器链处理,即不能被自动代理”)。
注意:当实例化后处理器以autowiring或@Resource的方式引用其他bean,Spring容器在以类型匹配依赖注入的时候,可能会注入非指定的bean(例如:实例化后处理器实现类以Resource方式依赖bean,若set方法和被依赖的bean的名称一致或者被依赖bean未声明名称,则依赖注入会以类型匹配的方式注入,此时可能会注入非指定的bean)。这也会导致自动代理或其他方式的实例化后处理器处理失败。
2.1.3bean实例初始化后处理器示例
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接口
2.2.1beanfactory后处理器
通过实现BeanFactoryPostProcessor接口,可以读取容器所管理的bean的配置元数据,在bean完成实例化之前进行更改,这些bean称之为beanfactory后处理器。
BeanFactoryPostProcessors与BeanPostProcessor接口的异同点:
相同点:
都是容器级别的后处理器
都可配置多个后处理器,并通过实现Ordered接口,指定执行顺序
都是针对接口声明的容器中所管理的bean进行处理,在有层级结构的容器中,不能处理其他容器中的bean,即使两个容器是同一层次
都是只需要在容器中和普通bean一样声明,容器会自动检测到,并注册为后处理器
会忽略延迟初始化属性配置
不同点:
BeanFactoryPostProcessors接口在bean**实例化前处理bean的配置元数据,BeanPostProcessor接口在bean实例化后处理bean的实例**
BeanFactoryPostProcessors接口也能通过BeanFactory.getBean()方法获取bean的实例,这样会引起bean的实例化。由于BeanFactoryPostProcessors后处理器是在所有bean实例化之前执行,通过BeanFactory.getBean()方法会导致提前实例化bean,从而打破容器标准的生命周期,这样可能会引起一些负面的影响(例如:提前实例化的bean会忽略bean实例化后处理器的处理)。
2.2.2Spring内置及自定义beanfactory后处理器
Spring内置了一些beanfactory后处理器(例如:PropertyPlaceholderConfigurer和PropertyOverrideConfigurer)。同时也支持实现BeanFactoryPostProcessor接口,自定义beanfactory后处理器。下面说说Spring内置的两个后处理器和自定义后处理器。
PropertyPlaceholderConfigurer
Spring为了避免主要的XML定义文件的修改而引起的风险,提供了配置分离,可以将一些可能变更的变量配置到属性配置文件中,并在XML定义文件中以占位符的方式引用。这样,修改配置只需要修改属性配置文件即可。PropertyPlaceholderConfigurer用于检测占位符,并替换占位符为配置属性值。示例如下:
PropertyPlaceholderConfigurer通过jdbc.properties属性配置文件,在运行时,将dataSource这个bean中数据库相关信息的属性占位符替换成对应的配置值。
XML配置如下:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations" value="classpath:com/foo/jdbc.properties"/> </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>
属性配置文件jdbc.properties如下:
jdbc.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:hsql://production:9002 jdbc.username=sa jdbc.password=root
PropertyPlaceholderConfigurer不仅支持属性配置文件的读取,也支持读取系统属性。通过systemPropertiesMode属性值可配置读取优先级。各种取值说明如下:
0:不读取系统属性
1:若引用的属性配置文件中未检索到对应占位符的配置,则读取系统属性。默认为1
2:先读取系统属性,再读取引用的属性配置文件。这种配置可能导致系统属性覆盖配置文件。
PropertyOverrideConfigurer
PropertyOverrideConfigurer类可以通过引用属性配置文件,直接给容器中的bean赋值。当一个bean的属性被多个PropertyOverrideConfigurer类实例赋值时,最后一个的值会覆盖前面的。
还是以上面给上面的dataSource的bean赋值为例:
PropertyOverrideConfigurer类对属性配置文件的引用使用一个新的方式,如下:
<context:property-override location="classpath:override.properties"/>
override.properties属性配置文件的属性的命名规则和上面不同(上面例子中需要保证属性名和占位符一致),命名规则是beanName.property
dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql:mydb dataSource.username=sa dataSource.password=root
支持复合属性的赋值,但是要保证引用被赋值属性的对象非空
例如:foo.fred.bob.sammy=123
自定义bean factory后处理器
自定义bean factory后处理器就是实现BeanFactoryPostProcessor接口,完成对Spring容器管理的bean的配置元数据进行修改。例如:修改类属性注入的值,示例如下:
定义一个用户类UserBean
public class UserBean { private String userName; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } }
Spring XML配置文件配置用户类,并给用户名属性userName注入值haha
<bean class="name.liuxi.spring.ext.BeanFactoryPostProcessorService"/> <bean id="user" class="name.liuxi.spring.ext.UserBean"> <property name="userName" value="haha"/> </bean>
下面是自定义的bean factory后处理器,修改属性userName的值为heihei
public class BeanFactoryPostProcessorService implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("BeanFactoryPostProcessorService postProcessBeanFactory method execut..."); BeanDefinition bd = beanFactory.getBeanDefinition("user"); MutablePropertyValues pv = bd.getPropertyValues(); if(pv.contains("userName")) { pv.addPropertyValue("userName", "heihei"); } } }
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
The above is the detailed content of Detailed explanation of Spring life cycle and container extension usage. For more information, please follow other related articles on the PHP Chinese website!