对Spring容器中Bean的生命周期解析
1. 生命周期简介
Bean 的生命周期:
Bean创建 —》初始化 —》销毁的过程
Spring 容器管理 bean 的生命周期:
我们可以自定义初始化和销毁的方法,容器在 bean 进行到对应生命周期的的时候调用我们自定义的初始化和销毁方法
1、Bean 的构造(对象创建):
单实例时,在容器启动时创建对象
多实例时,在每次获取 bean 的时候创建对象
2、Bean 的初始化:
对象创建好时,且属性已赋值完成后,调用初始化方法
3、Bean 的销毁
Spring 容器关闭时进行 bean 的销毁
2. @Bean指定初始化和销毁方法
在 @Bean 注解的源码中,存在两个属性:initMethod
、destroyMethod
即可以通过该属性指定被 @Bean 注解标注的组件的初始化方法和销毁方法
源码如下:
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
... ...
/**
* The optional name of a method to call on the bean instance during initialization.
* Not commonly used, given that the method may be called programmatically directly
* within the body of a Bean-annotated method.
* <p>The default value is {@code ""}, indicating no init method to be called.
*/
String initMethod() default "";
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}
创建 Bean 实体类:
package com.jiker.bean;
public class BeanDemo1 {
public BeanDemo1() {
// TODO Auto-generated constructor stub
System.out.println("BeanDemo1 constructor...");
}
public void init() {
System.out.println("BeanDemo1 init...");
}
public void destroy() {
System.out.println("BeanDemo1 destroy...");
}
}
创建配置类,并注入 bean(默认为单实例对象)
使用 @Bean 注解中的两个属性指定初始化和销毁方法
package com.jiker.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.jiker.bean.BeanDemo1;
@Configuration
public class MainConfig {
@Bean(initMethod = "init",destroyMethod = "destroy")
public BeanDemo1 beanDemo1() {
return new BeanDemo1();
}
}
测试
package com.jiker.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.jiker.config.MainConfig;
public class TestBean {
@Test
public void m01() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
System.out.println("Spring 容器创建...");
//关闭容器
applicationContext.close();
}
}
结果:
多实例对象测试
@Scope("prototype")
@Bean(initMethod = "init",destroyMethod = "destroy")
public BeanDemo1 beanDemo1() {
此时,运行时仅创建了 Spring 容器,并没有初始化容器中的对象
若获取 bean 后,容器关闭时不再销毁 bean,即:容器不管理多实例 bean 的生命周期
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
System.out.println("Spring 容器创建...");
applicationContext.getBean("beanDemo1");
//关闭容器
applicationContext.close();
3. InitializingBean和DisposableBean
InitializingBean
:由bean实现的接口,当bean工厂设置了所有属性后,需要作出反应:例如,执行自定义初始化,或者只检查是否设置了所有强制属性。
public interface InitializingBean {
/**
* Invoked by a BeanFactory after it has set all bean properties supplied
* (and satisfied BeanFactoryAware and ApplicationContextAware).
* <p>This method allows the bean instance to perform initialization only
* possible when all bean properties have been set and to throw an
* exception in the event of misconfiguration.
* @throws Exception in the event of misconfiguration (such
* as failure to set an essential property) or if initialization fails.
*/
void afterPropertiesSet() throws Exception;
}
DisposableBean
:接口将由希望在销毁时释放资源的bean实现。如果beanfactory处理缓存的单例,那么它应该调用destroy方法。应用程序上下文应该在关闭时释放它的所有单例
public interface DisposableBean {
/**
* Invoked by a BeanFactory on destruction of a singleton.
* @throws Exception in case of shutdown errors.
* Exceptions will get logged but not rethrown to allow
* other beans to release their resources too.
*/
void destroy() throws Exception;
}
即:可以创建一个实体类,分别实现 InitializingBean 和 DisposableBean 接口,这样 Spring 容器就会在对应的时期调用对应的接口方法,完成 bean 的初始化或销毁
BeanDemo2.java
:
package com.jiker.bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
//将该实例注入容器中
@Component
public class BeanDemo2 implements InitializingBean,DisposableBean {
public BeanDemo2() {
// TODO Auto-generated constructor stub
System.out.println("BeanDemo2 constructor...");
}
//实现DisposableBean中的方法
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println("BeanDemo2 DisposableBean.destroy ...");
}
//实现InitializingBean中的方法
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("BeanDemo2 InitializingBean.afterPropertiesSet ...");
}
}
使用 @ComponentScan 包扫描方式将 BeanDemo2 注册入容器
@ComponentScan("com.jiker.bean")
@Configuration
public class MainConfig {
4. @PostConstruct&@PreDestroy
使用 JSR250 中的注解:
@PostConstruct:在 bean 创建完成并且属性赋值完成后,来执行标注该注解的方法
@PreDestroy:在容器销毁 bean 之前通知我们进行清理工作
package com.jiker.bean;
import org.springframework.stereotype.Component;
@Component
public class BeanDemo3 {
public BeanDemo3() {
// TODO Auto-generated constructor stub
System.out.println("BeanDemo3 constructor...");
}
@PostConstruct
public void init() {
System.out.println("BeanDemo3 init...");
}
@PreDestroy
public void destroy() {
System.out.println("BeanDemo3 destroy...");
}
}
5. BeanPostProcessor后置处理器
Spring 为我们提供了一种组件:BeanPostProcessor[interface]
;意为 bean 的后置处理器
在 bean 初始化前后进行一些处理工作;
postProcessBeforeInitialization():在已经创建好了 bean 实例之后,且在任何初始化之前工作
postProcessAfterInitialization():在初始化之后工作
5.1 后置处理器实现
源码:
public interface BeanPostProcessor {
/**
* Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
* or a custom init-method). The bean will already be populated with property values.
* The returned bean instance may be a wrapper around the original.
* @param bean the new bean instance
* @param beanName the name of the bean
* @return the bean instance to use, either the original or a wrapped one;
* if {@code null}, no subsequent BeanPostProcessors will be invoked
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
*/
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
/**
* Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
* or a custom init-method). The bean will already be populated with property values.
* The returned bean instance may be a wrapper around the original.
* <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
* instance and the objects created by the FactoryBean (as of Spring 2.0). The
* post-processor can decide whether to apply to either the FactoryBean or created
* objects or both through corresponding {@code bean instanceof FactoryBean} checks.
* <p>This callback will also be invoked after a short-circuiting triggered by a
* {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
* in contrast to all other BeanPostProcessor callbacks.
* @param bean the new bean instance
* @param beanName the name of the bean
* @return the bean instance to use, either the original or a wrapped one;
* if {@code null}, no subsequent BeanPostProcessors will be invoked
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
* @see org.springframework.beans.factory.FactoryBean
*/
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
实现后置处理器接口
package com.jiker.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessBeforeInitialization " + beanName + " =>" + bean);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessAfterInitialization " + beanName + " =>" + bean);
return bean;
}
}
5.2 BeanPostProcessor原理
使用 DEBUG 方式查看方法栈
TestBean.m01() line: 13
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
创建 IOC 容器
AnnotationConfigApplicationContext.<init>(Class<?>...) line: 84
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
刷新容器
AnnotationConfigApplicationContext(AbstractApplicationContext).refresh() line: 543
public void refresh() throws BeansException, IllegalStateException {
... ...
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
... ...
}
初始化所有剩下的单实例对象
... ...//试着获取 bean,若是第一次获取,则创建 bean
DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).doCreateBean(String, RootBeanDefinition, Object[]) line: 555
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
populateBean(beanName, mbd, instanceWrapper) 方法既是通过各种判断为 bean 赋值
initializeBean(beanName, exposedObject, mbd) 即是后置处理器的调用,源码如下:
... ...
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
... ...
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
... ...
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
... ...
initializeBean方法中存在着 invokeInitMethods,即是初始化 bean,在其之前会调用 applyBeanPostProcessorsBeforeInitialization
在其后会调用 applyBeanPostProcessorsAfterInitialization
DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).applyBeanPostProcessorsBeforeInitialization(Object, String) line: 409
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
后置处理器中 XXXPostProcessBeforeInitialization 方法的原理:遍历得到容器中所有的 BeanPostProcessor,
挨个执行 beforeInitialization 方法,一旦方法返回 NULL 时,跳出循环,不会再执行后面的后者处理器
5.3 BeanPostProcessor在Spring底层的使用
BeanPostProcessor 接口的所有实现类:
示例:ApplicationContextAwareProcessor:给 bean 中注入 IOC容器
class ApplicationContextAwareProcessor implements BeanPostProcessor {
... ...
@Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
... ...
}
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
postProcessBeforeInitialization():判断传入的 bean 中是否实现了 XXXAware 接口,
如果是的话则执行 invokeAwareInterfaces()
invokeAwareInterfaces():初始化方法,给 bean 注入值,判断实现的是哪一个 Aware
若当前是 ApplicationContextAware,则调用 setApplicationContext,给 传入的 bean 注入 applicationContext 组件
时间:2019.6.24 10:11