一、Bean的生命周期管理
- bean的实例化:调用bean的构造方法,我们可以在bean的无参构造方法中执行相应的逻辑。
- bean的初始化:在初始化时,可以通过BeanPostProcessor的postProcessBeforeInitialization()方法和postProcessAfterInitialization()方法进行拦截,执行自定义的逻辑;通过@PostConstruct注解、InitializingBean和init-method来指定bean初始化前后执行的方法,在该方法中咱们可以执行自定义的逻辑。
- bean的销毁:可以通过@PreDestroy注解、DisposableBean和destroy-method来指定bean在销毁前执行的方法,在该方法中咱们可以执行自定义的逻辑。
1.通过@Bean指定init-method和destroy-method
@Bean(initMethod="init", destroyMethod="destroy") public Car car() { return new Car(); }
使用时机:
- 初始化方法:对象创建完成,如果对象中存在一些属性,并且这些属性也都赋好值之后,那么就会调用bean的初始化方法。
- 销毁的方法:可以对数据源的连接等信息进行关闭和清理。
单实例 | 多实例 | |
初始化 | 对于单实例bean来说,在Spring容器创建完成后,Spring容器会自动调用bean的初始化方法 | 在每次获取bean对象的时候,调用bean的初始化方法 |
销毁 | 在容器关闭的时候,会调用bean的销毁方法 | Spring容器不会管理这个bean,也就不会自动调用这个bean的销毁方法了 |
2.通过让bean实现InitializingBean和DisposableBean两个接口
(1)初始化bean
Spring为bean提供了两种初始化的方式,实现InitializingBean接口(也就是要实现该接口中的afterPropertiesSet方法),或者在配置文件或@Bean注解中通过init-method来指定,两种方式可以同时使用。
- 实现InitializingBean接口是直接调用afterPropertiesSet()方法,与通过反射调用init-method指定的方法相比,效率相对来说要高点。但是init-method方式消除了对Spring的依赖。
- 如果调用afterPropertiesSet方法时出错,那么就不会调用init-method指定的方法了。
(2)销毁bean
- 实现org.springframework.beans.factory.DisposableBean接口的bean在销毁前,Spring将会调用DisposableBean接口的destroy()方法。
- 使用destroy-method
前者与Spring耦合高,使用类型强转.方法名(),效率高;后者耦合低,使用反射,效率相对来说较低。
【 注意】多实例bean的生命周期不归Spring容器来管理,这里的DisposableBean接口中的方法是由Spring容器来调用的,所以如果一个多实例bean实现了DisposableBean接口是没有啥意义的,因为相应的方法根本不会被调用,当然了,在XML配置文件中指定了destroy方法,也是没有任何意义的。所以,在多实例bean情况下,Spring是不会自动调用bean的销毁方法的。
package com.meimeixia.bean; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @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..."); } /** * 会在bean创建完成,并且属性都赋好值以后进行调用 */ @Override public void afterPropertiesSet() throws Exception { // TODO Auto-generated method stub System.out.println("cat afterPropertiesSet..."); } }
3.使用JSR-250规范里面定义的@PostConstruct和@PreDestroy两个注解
@PostConstruct注解是Java中的注解,并不是Spring提供的注解。@PostConstruct和@PreDestroy是Java规范JSR-250引入的注解,定义了对象的创建和销毁工作,同一期规范中还有@Resource注解,Spring也支持了这些注解。
package com.meimeixia.bean; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.springframework.stereotype.Component; /** * * @author liayun * */ @Component public class Dog { public Dog() { System.out.println("dog constructor..."); } // 在对象创建完成并且属性赋值完成之后调用 @PostConstruct public void init() { System.out.println("dog...@PostConstruct..."); } // 在容器销毁(移除)对象之前调用 @PreDestroy public void destory() { System.out.println("dog...@PreDestroy..."); } }
注解 | 源码 | 执行顺序 |
@PostConstruct |
在bean创建完成并且属性赋值完成之后,来执行初始化方法。 Constructor(构造方法)→@Autowired(依赖注入)→@PostConstruct(注释的方法) |
|
@PreDestroy |
在容器销毁bean之前通知我们进行清理工作。 调用destroy()方法→@PreDestroy→destroy()方法→bean销毁 |
4.通过让bean实现BeanPostProcessor接口
(1)BeanPostProcessor是什么?
BeanPostProcessor是一个接口,其中有两个方法,Spring容器中的每一个bean对象初始化前后,都会执行BeanPostProcessor接口的实现类中的这两个方法。
接口 | 调用时机 |
postProcessBeforeInitialization | 在bean实例化和属性设置之后,自定义初始化方法之前被调用 |
postProcessAfterInitialization | 在自定义初始化方法之后被调用 |
package com.meimeixia.bean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; /** * 后置处理器,在初始化前后进行处理工作 * @author liayun * */ @Component // 将后置处理器加入到容器中,这样的话,Spring就能让它工作了 public class MyBeanPostProcessor implements BeanPostProcessor, Ordered { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // TODO Auto-generated method stub System.out.println("postProcessBeforeInitialization..." + beanName + "=>" + bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { // TODO Auto-generated method stub System.out.println("postProcessAfterInitialization..." + beanName + "=>" + bean); return bean; } @Override public int getOrder() { // TODO Auto-generated method stub return 3; } }
当容器中存在多个BeanPostProcessor的实现类时,会按照它们在容器中注册的顺序执行。对于自定义的BeanPostProcessor实现类,还可以让其实现Ordered接口自定义排序。
(2)作用
后置处理器可用于bean对象初始化前后进行逻辑增强。Spring提供了BeanPostProcessor接口的很多实现类,例如AutowiredAnnotationBeanPostProcessor用于@Autowired注解的实现,AnnotationAwareAspectJAutoProxyCreator用于Spring AOP的动态代理等等。
(3)原理
在Spring中调用initializeBean()方法之前,还调用了populateBean()方法来为bean的属性赋值
在applyBeanPostProcessorsBeforeInitialization()方法中,会遍历所有BeanPostProcessor对象,然后依次执行所有BeanPostProcessor对象的postProcessBeforeInitialization()方法,一旦BeanPostProcessor对象的postProcessBeforeInitialization()方法返回null以后,则后面的BeanPostProcessor对象便不再执行了,而是直接退出for循环。
populateBean(beanName, mbd, instanceWrapper); // 给bean进行属性赋值 initializeBean(beanName, exposedObject, mbd) { applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); invokeInitMethods(beanName, wrappedBean, mbd); // 执行自定义初始化 applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }
(4)Spring底层对BeanPostProcessor的使用
bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxxBeanProcessor等。