Maison > Article > interface Web > Explication détaillée du cycle de vie de Spring et de l'utilisation de l'extension de conteneur
Cette fois, je vais vous apporter une explication détaillée de l'utilisation du cycle de vie de Spring et des extensions de conteneur. Quelles sont les précautions lors de l'utilisation du cycle de vie Spring et des extensions de conteneur. ? Voici des cas pratiques, jetons un coup d'œil.
Ce qui suit est l'introduction principale :
Configuration de la méthode de rappel d'initialisation du cycle de vie au niveau de la classe, interface InitializingBean et annotation PostConstruct
Interface BeanPostProcessor étendue au niveau du conteneur et interface BeanFactoryPostProcessor
1. Rappel du cycle de vie au niveau de la classe
1.1init-méthode
Référence : méthode Springbeanxsdinit
init-method est un élément de configuration lors de la déclaration d'un bean dans le fichier de configuration Spring . La valeur de l'élément de configuration de la méthode init est une méthode sans paramètre dans la classe, mais elle peut lever une exception . Cette méthode sera appelée une fois que le conteneur Spring aura instancié l'objet et défini les valeurs des propriétés.
Les fonctions que la méthode init peut implémenter sont cohérentes avec l'interface InitializingBean et les annotations PostConstruct
Les fichiers de configuration Spring et les classes de test sont les suivants :
<bean id = "initMethodBeanService" class="name.liuxi.spring.ext.InitMethodBeanService" init-method="init"> <property name="f2" value="2"/> </bean>
Les classes de tests sont les suivantes :
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..."); } }
Le résultat de l'exécution s'imprime comme suit :
InitMethodBeanService static block execute... InitMethodBeanService construct method execute... InitMethodBeanService setF2 method execute... InitMethodBeanService init method execute... test method execute...
1.2Initialisation de l'interfaceBean
Référence : document officiel du printemps beans-factory-lifecycle-initializingbean
L'interface InitializingBean déclare une méthode afterPropertiesSet, qui sera appelée une fois que le conteneur Spring aura instancié l'objet et défini les valeurs des propriétés. La fonction implémentée par la méthode init ci-dessus est cohérente, Spring ne recommande donc pas d'utiliser l'interface InitializingBean.
L'exemple est relativement simple et ne sera pas répertorié ici
1.3Annotation PostConstruct
Traduction : Document officiel du printemps beans-postconstruct-and-predestroy-annotations
L'annotation @PostConstruct est une méthode de rappel du cycle de vie qui a le même effet que les interfaces init-method et InitializingBean
@PostConstruct public void postConstruct(){ System.out.println("PostConstructService postConstruct method execute..."); }
Résumez les trois méthodes de rappel du cycle de vie ci-dessus, méthode init, interface InitializingBean, annotation @PostConstruct
1. Ils sont tous des traitements post-instanciation pour une seule classe
2. Le temps d'exécution est entièrement appelé après l'instanciation de la classe et l'injection des variables membres
3. Pour la méthode init, vous pouvez également configurer la méthode d'initialisation par défaut sous l'élément beans du fichier de configuration Spring. L'élément de configuration est default-init-method
. 4. Si les méthodes d'initialisation configurées selon les trois méthodes ci-dessus sont différentes, l'ordre d'exécution est : @PostConstruct méthode d'annotation–>InitializingBean's afterPropertiesSet–>init-method ; les méthodes ne sont exécutées qu'une seule fois (voir : document officiel de Spring beans-factory-lifecycle-combined-effect)
5. Il existe une méthode de rappel d'initialisation et une méthode de rappel de destruction correspondante. La méthode d'annotation @PostConstruct –>InitializingBean's afterPropertiesSet–>init-method correspond à la méthode d'annotation @PreDestroy–>DisposableBean's destroy–>destroy-method
2. Expansion au niveau du conteneur
Traduction : Document officiel du printemps 3.8ContainerExtensionPoints
Dans des circonstances normales, les développeurs n'ont pas besoin de personnaliser une sous-classe de ApplicationContext pour étendre le conteneur SpringIOC. Le conteneur SpringIOC peut étendre le conteneur SpringIOC via certaines interfaces exposées en externe.
2.1Interface BeanPostProcessor
2.1.1Post-processeur d'initialisation de l'instance du bean et chaîne de post-processeur
L'interface BeanPostProcessor définit deux méthodes de rappel au niveau du conteneur, postProcessBeforeInitialization et postProcessAfterInitialization, qui sont utilisées pour un traitement logique après l'initialisation de l'instance et seront traitées pour toutes les instances du conteneur. La classe qui implémente l'interface BeanPostProcessor est appelée post-processeur d'initialisation de l'instance du bean.
Si plusieurs post-processeurs d'initialisation d'instance sont intégrés dans le conteneur SpringIOC, l'ensemble de ces post-processeurs est appelé chaîne de post-processeurs d'initialisation d'instance de bean.
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中文网其它相关文章!
推荐阅读:
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!