Bean的生命周期 : 创建bean对象 – 属性赋值 – 初始化方法调用前的操作 – 初始化方法 – 初始化方法调用后的操作 – …-- 销毁前操作 – 销毁方法的调用。
先放一张图吧。
【1】init-method和destroy-method
bean 标签有两个重要的属性(init-method 和 destroy-method
)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解(@PostConstruct 和@PreDestroy
)。
自定义初始化方法和销毁方法两种方式:xml配置和注解。
① xml配置
<bean id="person" class="com.core.Person" scope="singleton" init-method="init" destroy-method="cleanUp" autowire="byName" lazy-init="true" > </bean>
② 注解配置
@Scope("singleton") @Lazy @Bean(name="person",initMethod="init",destroyMethod="cleanUp", autowire=Autowire.BY_NAME) public Person person01(){ return new Person("lisi", 20); }
单实例bean在容器创建完成前会进行创建并初始化,在容器销毁的时候进行销毁。多实例bean(scope=prototype)在第一次获取该bean实例时才会创建并初始化,且容器不负责该bean的销毁。
【2】InitializingBean 和DisposableBean
InitializingBean 接口
public interface InitializingBean { void afterPropertiesSet() throws Exception; }
在BeanFactory设置完bean属性后执行
需要被bean实现的接口,一旦bean的属性被BeanFactory设置后需要做出反应: 如,执行自定义初始化,或者仅仅是检查是否设置了所有强制属性。
实现InitializingBean 的可替代方式为给bean指定一个自定义的init-method,例如在一个xml bean 定义中。
在bean的属性设置之后进行操作,不返回任何值但是允许抛出异常。
DisposableBean接口
public interface DisposableBean { void destroy() throws Exception; }
被bean实现的接口,在销毁时释放资源,在Bean销毁的时候调用该方法。
如果销毁一个缓存的单例,一个BeanFactory 可能会调用这个销毁方法。
在容器关闭时,应用上下文会销毁所有的单例bean。
一种替代实现DisposableBean 接口的方案为指定一个自定义的destroy-method方法,例如在一个xml bean定义中。
自定义bean实现上述两个接口
@Component public class Cat implements InitializingBean,DisposableBean { public Cat(){ System.out.println("cat constructor..."); } @Override public void destroy() throws Exception { // TODO Auto-generated method stub System.out.println("cat...destroy..."); } @Override public void afterPropertiesSet() throws Exception { // TODO Auto-generated method stub System.out.println("cat...afterPropertiesSet..."); } }
测试结果
cat constructor... cat...afterPropertiesSet... 容器创建完成... 四月 08, 2018 6:35:46 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose 信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@11028347: startup date [Sun Apr 08 18:35:46 CST 2018]; root of context hierarchy cat...destroy...
【3】@PostConstruct和@PreDestroy
使用JSR250规范定义的两个注解:
@PostConstruct
:PostConstruct
注解作用在方法上,在依赖注入完成后进行一些初始化操作。这个方法在类被放入service之前被调用,所有支持依赖项注入的类都必须支持此注解。@PreDestroy
:在容器销毁bean之前通知我们进行清理工作
自定义类使用上述两个注解
@Component public class Dog implements ApplicationContextAware { //@Autowired private ApplicationContext applicationContext; public Dog(){ System.out.println("dog constructor..."); } //对象创建并赋值之后调用 @PostConstruct public void init(){ System.out.println("Dog....@PostConstruct..."); } //容器移除对象之前 @PreDestroy public void detory(){ System.out.println("Dog....@PreDestroy..."); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // TODO Auto-generated method stub this.applicationContext = applicationContext; } }
测试结果如下:
dog constructor... Dog....@PostConstruct... 容器创建完成... 四月 08, 2018 6:42:11 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose 信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@11028347: startup date [Sun Apr 08 18:42:10 CST 2018]; root of context hierarchy Dog....@PreDestroy...
【4】BeanPostProcessor-Bean后置处理器
① 什么是bean后置处理器
Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理。Bean 后置处理器对 IOC 容器里的所有 Bean 实例逐一处理, 而非单一实例。其典型应用是: 检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性。
在bean初始化前后进行一些处理工作
postProcessBeforeInitialization
:在初始化之前工作postProcessAfterInitialization
:在初始化之后工作
其接口源码如下:
public interface BeanPostProcessor { Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }
自定义MyBeanPostProcessor实现该接口
/** * 后置处理器:初始化前后进行处理工作 * 将后置处理器加入到容器中 */ @Component public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("BeanPostProcessor.postProcessBeforeInitialization..."+beanName+"=>"+bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("BeanPostProcessor.postProcessAfterInitialization..."+beanName+"=>"+bean); return bean; } }
② BeanPostProcessor原理
AbstractAutowireCapableBeanFactory中关于bean和BeanPostProcessor执行次序由上到下
//给bean进行属性赋值 populateBean(beanName, mbd, instanceWrapper); //然后调用initializeBean方法 Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); //执行自定义初始化 invokeInitMethods(beanName, wrappedBean, mbd); applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } //给be
AbstractAutowireCapableBeanFactory.initializeBean源码如下:
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { invokeAwareMethods(beanName, bean); return null; } }, getAccessControlContext()); } else { //调用意识/通知方法 invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { //调用bean后置处理器的前置方法 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } //调用初始化方法 try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { // //调用bean后置处理器的后置方法 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; } protec
AbstractAutowireCapableBeanFactory.invokeInitMethods方法源码如下:
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } //调用InitializingBean.afterPropertiesSet if (System.getSecurityManager() != null) { try { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { @Override public Object run() throws Exception { ((InitializingBean) bean).afterPropertiesSet(); return null; } }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { ((InitializingBean) bean).afterPropertiesSet(); } } //调用自定义初始化方法 if (mbd != null) { String initMethodName = mbd.getInitMethodName(); if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { invokeCustomInitMethod(beanName, bean, mbd); } } }
【5】Spring底层使用的BeanPostProcessor
Spring框架底层存在大量BeanPostProcessor,如下图:
示例一 :BeanValidationPostProcessor是处理bean校验
其Javadoc如下:
//为spring管理的bean,校验JSR-303注解约束。如果校验不通过则在调用bean的init method前抛出初始化异常 public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean { private Validator validator; private boolean afterInitialization = false; //... }
示例二:ApplicationContextAwareProcessor帮助获取容器上下文
其Javadoc如下:
// 传递ApplicationContext class ApplicationContextAwareProcessor implements BeanPostProcessor { private final ConfigurableApplicationContext applicationContext; private final StringValueResolver embeddedValueResolver; //... }
如【3】中的dog类为例,其debug示意图如下:
【6】初始化和销毁方式测试
① 如果一个bean 综合应用下面六种种方式,执行顺序会怎样呢
Bean类如下:
public class Person implements InitializingBean,DisposableBean { private String name; private Integer age=1; public Person(String name, Integer age) { this.name = name; this.age = age; System.out.println("Person(String name, Integer age) constructor"+this); } public Person() { super(); System.out.println("Person() constructor"+age); } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } // 自定义init方法 public void init(){ System.out.println("-----Person.init()-----"+this); } // 自定义销毁方法 public void cleanUp(){ System.out.println("-----Person.cleanUp()-----"+this); } // InitializingBean的实现方法 @Override public void afterPropertiesSet() throws Exception { System.out.println("-----InitializingBean.afterPropertiesSet()-----"+this); } //DisposableBean 的实现方法 @Override public void destroy() throws Exception { System.out.println("-----DisposableBean.destroy()-----"+this); } //对象创建并赋值之后调用 @PostConstruct public void init2(){ System.out.println("-----@PostConstruct-----"+this); } //容器移除对象之前 @PreDestroy public void destory2(){ System.out.println("-----@PreDestroy-----"+this); } }
配置类如下:
@Scope("singleton") @Bean(name="person",initMethod="init",destroyMethod="cleanUp", autowire= Autowire.BY_NAME) public Person person01(){ return new Person("lisi", 20); }
测试结果如下:
// 创建并初始化 Person(String name, Integer age) constructorPerson{name='lisi', age=20} -----@PostConstruct-----Person{name='lisi', age=20} -----InitializingBean.afterPropertiesSet()-----Person{name='lisi', age=20} -----Person.init()-----Person{name='lisi', age=20} //容器将要销毁 -----@PreDestroy-----Person{name='lisi', age=20} -----DisposableBean.destroy()-----Person{name='lisi', age=20} -----Person.cleanUp()-----Person{name='lisi', age=20}
即,最先使用bean的构造器为bean属性赋值,接着JSR250规范定义的两个注解,其次是InitializingBean和DisposableBean接口,最后才是我们自定义的初始化方法和销毁方法。注意,这里还没有引入BeanPostProcessor。
② 在①的基础上添加BeanPostProcessor
实例化bean并进行初始化
//调用构造方法 Person(String name, Integer age) constructorPerson{name='lisi', age=20} //bean初始化前 BeanPostProcessor.postProcessBeforeInitialization...person=>Person{name='lisi', age=20} //初始化操作 -----@PostConstruct-----Person{name='lisi', age=20} -----InitializingBean.afterPropertiesSet()-----Person{name='lisi', age=20} -----Person.init()-----Person{name='lisi', age=20} //bean初始化后操作 BeanPostProcessor.postProcessAfterInitialization...person=>Person{name='lisi', age=20}
过程如下:类构造函数-->BeanPostProcessor-->@PostConstruct-->InitializingBean-->init()-->BeanPostProcessor
销毁bean
-----@PreDestroy-----Person{name='lisi', age=20} -----DisposableBean.destroy()-----Person{name='lisi', age=20} -----Person.cleanUp()-----Person{name='lisi', age=20}
完整图示如下(同颜色的说明相对应):
在调用bean的构造函数时会根据入参为bean属性赋值,如果入参为空则会给bean属性赋予默认值,引用类型为null,基本类型比如int为0。
【7】 @Autowired注解的值何时放入?
public Person(String name, Integer age) { this.name = name; this.age = age; System.out.println("Person(String name, Integer age) constructor"+this); System.out.println(" @Autowired adviceService:"+adviceService); } @Override public void setBeanName(String name) { System.out.println(" @Autowired adviceService:"+adviceService); System.out.println("BeanNameAware--setBeanName...."+name); }
测试结果:
// 如下是构造函数中打印 Person(String name, Integer age) constructorPerson{name='lisi', age=20} @Autowired adviceService:null // 如下 是setBeanName方法中打印 @Autowired adviceService:com.recommend.service.impl.SysAdviceServiceImpl@5a739e57 BeanNameAware--setBeanName....person
那么也就是说,在类的构造函数调用、setXXX属性后,开始执行@Autowired依赖注入。这个过程发生在setBeanName时机之前。
那么具体什么时候哪个类完成的 @Autowired注解注入依赖呢?
在类被实例化后由BeanPostProcessor完成的,哪个BeanPostProcessor?
具体是由AutowiredAnnotationBeanPostProcessor
完成的:
【8】如果bean实现了XXXAware接口呢?
这里比如Person实现了BeanNameAware、BeanFactoryAware以及ApplicationContextAware接口。
如果这个 Bean 已经实现了 BeanNameAware 接口,会调用它实现的setBeanName(String) 方法,此处传递的就是 Spring 配置文件中 Bean 的 id 值。
如果这个 Bean 已经实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory,
setBeanFactory(BeanFactory)传递的是 Spring 工厂自身(可以用这个方式来获取其它 Bean,只需在 Spring 配置文件中配置一个普通的 Bean 就可以)。
如果这个 Bean 已经实现了 ApplicationContextAware 接口,会调用
setApplicationContext(ApplicationContext)方法,传入 Spring 上下文(同样这个方式也可以实现步骤 setBeanFactory 的内容,但比 setBeanFactory 更好,因为ApplicationContext 是 BeanFactory 的子接口,有更多的实现方法)
public class Person implements InitializingBean, DisposableBean, BeanNameAware, BeanFactoryAware, ApplicationContextAware { private String name; private Integer age=1; public Person(String name, Integer age) { this.name = name; this.age = age; System.out.println("Person(String name, Integer age) constructor"+this); } public Person() { super(); System.out.println("Person() constructor"+age); } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; System.out.println("setName方法..."+name); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } // 自定义init方法 public void init(){ System.out.println("-----Person.init()-----"+this); } // 自定义销毁方法 public void cleanUp(){ System.out.println("-----Person.cleanUp()-----"+this); } // InitializingBean的实现方法 @Override public void afterPropertiesSet() throws Exception { System.out.println("-----InitializingBean.afterPropertiesSet()-----"+this); } //DisposableBean 的实现方法 @Override public void destroy() throws Exception { System.out.println("-----DisposableBean.destroy()-----"+this); } //对象创建并赋值之后调用 @PostConstruct public void init2(){ System.out.println("-----@PostConstruct-----"+this); } //容器移除对象之前 @PreDestroy public void destory2(){ System.out.println("-----@PreDestroy-----"+this); } @Override public void setBeanName(String name) { System.out.println("BeanNameAware--setBeanName...."+name); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("BeanFactoryAware.setBeanFactory...."+beanFactory); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("ApplicationContextAware.setApplicationContext...."+applicationContext); } }
同样在配置类中配置person bean如下
@Configuration public class MyConfiguration { @Scope("singleton") @Bean(name="person",initMethod="init",destroyMethod="cleanUp", autowire= Autowire.BY_NAME) public Person person01(){ return new Person("lisi", 20); } }