学习了 bean创建 和 bean加载 之后我们了解了 Spring IOC 容器对于托管对象bean的管理,bean的生命周期也完全有 Spring IOC 容器管理。Spring的ioc容器功能非常强大,负责Spring的Bean的创建和管理等功能。而Spring 的 bean 是整个Spring应用中很重要的一部分,了解Spring Bean的生命周期对我们了解整个spring框架会有很大的帮助
BeanFactory 和 ApplicationContext 是 Spring 中两种非常重要的容器,功能分别如下:
BeanFactory:提供了创建bean和依赖注入的支持
ApplicationContext: 除了拥有 BeanFactory 的功能外,还增加了一些扩展功能,例如增加了事件传播,资源访问和国际化的消息访问等功能
下面分别介绍 ApplicationContext 和 BeanFactory 两种容器的 bean 的生命周期
首先看 ApplicationContext Bean 的生命周期图,如下所示:
ApplicationContext 容器,Bean 的生命周期流程大致如下:
对于 ApplicationContext 容器,当容器启动后,便会实例化所有的 bean,容器通过获取 BeanDefinition(bean定义) 对象中信息进行实例化。注意这一步仅仅是简单的实例化而已,并没有初始化和依赖注入,创建好的 bean 实例被包装成 BeanWrapper 对象,BeanWrapper 提供了设置对象属性的接口,从而避免了使用反射机制设置bean属性
实例化后的对象 BeanWrapper 此时是一个原生的状态,并没有进行任何属性的设置,包括依赖注入。 紧接着 Spring 会根据 BeanDefinition 中的信息进行依赖注入。
并通过 BeanWrapper 提供的设置属性的接口完成依赖注入
Spring 会检测该对象是否实现了 xxxAware 接口,并将相关的 xxxAware 实例注入给bean,如下所示:
1)、如果 Bean 实现了 BeanNameAware 接口,则会调用该接口的 setBeanName 方法,传入该 Bean 的 id,这样该 Bean 就获得了自己在配置文件中的 id
2)、如果 Bean 实现了 BeanFactoryAware 接口,则会该接口的 setBeanFactory 方法,传入该 Bean 的 BeanFactory,这样该 Bean 就获得了自己所在的 BeanFactory 对象
3)、如果 Bean 实现了 ApplicationContextAware 接口,则会调用该接口的 setApplicationContext 方法,传入该 Bean 的 ApplicationContext,这样该 Bean 就获得了自己所在的 ApplicationContext 对象
经过上述3个步骤之后,bean 对象已经被构造好了,如果你想要在对象使用前做一些自定义的处理的话,就可以通过实现 BeanPostProcessor 接口完成处理,该接口提供了两个重要的方法:
postProcessBeforeInitialization( Object bean, String beanName ) : 传入当前正在被初始化的 bean 和 beanName,此时可以对 bean 做自定义的处理,由于此方法会先于 InitialzationBean 接口方法执行,故此称为前置处理
postProcessAfterInitialization( Object bean, String beanName ) : 传入当前正在被初始化的 bean 和 beanName,此时可以对 bean 做自定义的处理,由于此方法会在 InitialzationBean 接口方法调用完成之后执行,故此称为后置处理
当 BeanPostProcessor 的前置处理之后,如果 bean 实现了 InitialzationBean 接口,则会调用 InitializingBean 接口的 afterPropertiesSet 方法
InitializingBean 接口只有一个方法,即 afterPropertiesSet(),它没有任何传参,因此不能对 bean 做任何的处理,但是可以实现一些额外的业务逻辑
Spring 为了降低对客户代码的侵入性,还给 bean 的配置提供了 init-method 属性,通过该属性用户可以配置想要执行的方法
经过此步骤之后,就可以正式使用该Bean了,对于 scope 为 singleton 类型的 Bean,Spring IOC 容器中会缓存该 bean 的实例,而对于 scope 为 prototype 类型的 Bean,每次被调用都会new一个新的对象,其生命周期就交给调用方管理了,不再由 Spring 容器对其进行管理了
容器关闭后,如果 Bean 实现了 DisposableBean 接口,则会调用该接口的 destroy 方法销毁bean
同样的,Spring 为了降低对客户代码的侵入性,还给 bean 的配置提供了 destroy-method 属性,通过该属性用户可以配置销毁bean后想要执行的方法
至此,整个 Bean 的生命周期结束
1)、自定义 BeanPostProcessor,代码如下:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* 自定义BeanPostProcessor
*
* @date 2019-12-24 11:23
**/
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean,
String beanName) throws BeansException {
System.out.println("BeanPostProcessor postProcessBeforeInitialization 方法被调用");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean,
String beanName) throws BeansException {
System.out.println("BeanPostProcessor postProcessAfterInitialization 方法被调用");
return bean;
}
}
2)、TestBean 实体类,代码如下:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* 测试bean
*
* @date 2019-12-24 11:17
**/
public class TestBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {
private String beanName;
private BeanFactory beanFactory;
private ApplicationContext applicationContext;
public TestBean() {
System.out.println("TestBean 构造方法被调用");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryAware 的 setBeanFactory 方法被调用");
this.beanFactory = beanFactory;
}
@Override
public void setBeanName(String name) {
System.out.println("BeanNameAware 的 setBeanName 方法被调用");
this.beanName = name;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("ApplicationContextAware 的 setApplicationContext 方法被调用");
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean 的 afterPropertiesSet 方法被调用");
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean 的 destroy 方法被调用");
}
public void myInitMethod(){
System.out.println("自定义的 myInitMethod 方法被调用");
}
public void myDestroyMethod(){
System.out.println("自定义的 myDestroyMethod 方法被调用");
}
}
3)、测试类代码如下:
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* ApplicationContext测试
*
* @date 2019-12-24 11:31
**/
public class ApplicationContextTest {
public static void main(String[] args) {
System.out.println("开始初始化ApplicationContext容器");
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application_context.xml");
System.out.println("ApplicationContext容器初始化完毕");
applicationContext.close();
}
}
4)、src/test/resources/application_context.xml 配置文件内容如下:
5)、运行结果如下:
开始初始化ApplicationContext容器
TestBean 构造方法被调用
BeanNameAware 的 setBeanName 方法被调用
BeanFactoryAware 的 setBeanFactory 方法被调用
ApplicationContextAware 的 setApplicationContext 方法被调用
BeanPostProcessor postProcessBeforeInitialization 方法被调用
InitializingBean 的 afterPropertiesSet 方法被调用
自定义的 myInitMethod 方法被调用
BeanPostProcessor postProcessAfterInitialization 方法被调用
ApplicationContext容器初始化完毕
DisposableBean 的 destroy 方法被调用
自定义的 myDestroyMethod 方法被调用
运行结果可以看出,和 ApplicationContext Bean 的生命周期图上的流程一致
BeanFactory Bean 的生命周期图,如下所示:
从上图中可知,BeanFactory Bean 的生命周期和 ApplicationContext Bean 的生命周期步骤上基本上一致,对于相同点这里不在做重复说明了,下面只分析其不同点:
1)、BeanFactory 容器不会调用 ApplicationContextAware 接口的 setApplicationContext 方法
2)、BeanPostProcessor 接口的 postProcessBeforeInitialzation 方法和 postProcessAfterInitialization 方法不会自动调用,即使 xml 中配置了 BeanPostProcessor 也没有用,必须自己通过代码手动注册
3)、BeanFactory 容器启动的时候,不会去实例化所有的 Bean,包括所有scope为singleton且非懒加载的 Bean 也是一样,而是在调用的时候(getBean 方法调用)才去实例化
自定义 BeanPostProcessor 、TestBean 和 配置文件内容全部不变,只有测试类修改了,如下所示:
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import com.springboot.demo.bean.MyBeanPostProcessor;
/**
* BeanFactory测试
*
* @date 2019-12-24 14:17
**/
public class BeanFactoryTest {
public static void main(String[] args) {
System.out.println("开始初始化BeanFactory容器");
ConfigurableBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("application_context.xml"));
System.out.println("BeanFactory容器初始化完毕");
// 这里必须手动注册 BeanPostProcessor
beanFactory.addBeanPostProcessor(new MyBeanPostProcessor());
// 必须调用 BeanFactory 的 getBean 方法,不然 bean 是不会实例化的,因为 BeanFactory 中的 bean 都是懒加载
beanFactory.getBean("testBean");
beanFactory.destroySingletons();
}
}
运行结果如下:
开始初始化BeanFactory容器
BeanFactory容器初始化完毕
TestBean 构造方法被调用
BeanNameAware 的 setBeanName 方法被调用
BeanFactoryAware 的 setBeanFactory 方法被调用
BeanPostProcessor postProcessBeforeInitialization 方法被调用
InitializingBean 的 afterPropertiesSet 方法被调用
自定义的 myInitMethod 方法被调用
BeanPostProcessor postProcessAfterInitialization 方法被调用
DisposableBean 的 destroy 方法被调用
自定义的 myDestroyMethod 方法被调用
运行结果可以看出,和 BeanFactory Bean 的生命周期图上的流程一致
对于 Bean 的生命周期管理有 ApplicationContext 和 BeanFactory,Spring 建议大家使用 ApplicationContext 方式获取 bean,而 BeanFactory 方式目前已经被 Spring 舍弃,不建议大家使用 BeanFactory 方式获取 bean
参考:
https://www.jianshu.com/p/3944792a5fff
https://www.zhihu.com/question/38597960