Spring Bean 生命周期
1. 配置 Bean
通过配置文件或者注解的形式,告诉 spring容器 哪些类是我们要注入容器的。
2. Bean的读取
在 spring 启动时,spring 会通过 BeanDefinitionReader 读取到我们配置的 Bean,将读取到的 Bean 存入 DefaultListableBeanFactory 类的 beanDefInitionMap 里(这里的 beanDefInitionMap 是一个 concurrentHashMap 类型的 Map 集合),每一个 Bean 都是一个 BeanDefInition 对象,这个对象封装了 Spring 对 Bean 的所有配置信息:类名,属性,构造方法参数,依赖,是否延迟加载,是否单例等。
3. 实例化阶段
在这个阶段,Spring 会将拿到的所有单例 Bean 进行实例化,在实例化的阶段,有几个 Spring 暴露给我们的接口可以使用。
3.1 BeanDefInitionRegistryPostProcessor:通常用来往 Spring 容器中注册新的 Bean
postProcessBeanFactory 方法与 BeanFactoryPostProcessor接口中的postProcessBeanFactory方法 功能一致,但是这个方法会在它之前触发
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
BeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClassName("com.cfz.entity.Student");
beanDefinitionRegistry.registerBeanDefinition("stu",rootBeanDefinition);
}
//与 BeanFactoryPostProcessor 功能一致
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)
throws BeansException {
}
}
3.2 BeanFactoryPostProcessor:通常用来修改已有的 Bean对象
在这个方法中也可以注册新的 Bean,但是 ConfigurableListableBeanFactory 内是没有注册 Bean 的方法的,需要转型为 DefaultListableBeanFactory
public class MyBeanFactoryProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
//修改
BeanDefinition stu = configurableListableBeanFactory.getBeanDefinition("stu");
stu.setBeanClassName("com.cfz.entity.User");
//注册
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
BeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClassName("com.cfz.entity.Student");
defaultListableBeanFactory.registerBeanDefinition("user",beanDefinition);
}
}
4. 初始化阶段
经过实例化后的 Bean 还只是一个“半成品”,则些 Bean 现在只是一个空壳。接下来赋予他们内容,才是重要部分。
4.1 Bean 实例的属性填充
为实例化好的 Bean 对象,注入属性,或者他们依赖的对象。在注入时有以下几种情况:
- 注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去;
- 注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没 有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作;
- 注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)
4.2 Aware接口属性注入
Aware接口是一种框架辅助属性注入的一种思想,其他框架中也可以看到类似的接口。框架具备高度封 装性,我们接 触到的一般都是业务代码,一个底层功能API不能轻易的获取到,但是这不意味着永远用 不到这些对象,如果用到了 ,就可以使用框架提供的类似Aware的接口,让框架给我们注入该对象 总结:处理器的作用,为Bean生命周期各个阶段提供扩展
spring中的aware接口主要是为了框架内部使用的,如果你的bean对象使用了aware接口,那么它就会和spring框架耦合,所以一般不建议自己使用。但是在阅读spring框架的源码时,你会发现很多地方都用到了aware接口,这是因为spring框架需要通过这些接口来获取和操作一些核心的组件或信息
public class User implements BeanNameAware, ApplicationContextAware, BeanFactoryAware {
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println(beanFactory);
}
@Override
public void setBeanName(String s) {
System.out.println(s);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println(applicationContext);
}
}
运行结果:
4.3 BeanPostProcessor的before()方法回调
这个方法会在bean的初始化方法调用之前被Spring容器执行。这个方法的参数是bean对象和bean的名称,这个方法的返回值也是bean对象,你可以在这个方法中对bean对象进行一些处理,或者返回一个新的对象
BeanPostProcessor的before()方法回调的作用是,让你可以在bean的初始化之前,对bean进行一些自定义的操作,比如修改bean的属性,添加一些逻辑,或者代理bean的方法等。你可以在一个容器中注册多个BeanPostProcessor的实现类,它们的before()方法回调会按照顺序依次执行,你可以通过实现Ordered接口来控制执行顺序
Ordered接口不会影响组件或者bean的加载顺序和实例化顺序,只会影响它们的执行顺序。例如,如果有多个BeanPostProcessor的实现类,它们的postProcessBeforeInitialization()方法会按照Ordered接口的顺序依次执行,而postProcessAfterInitialization()方法则会按照相反的顺序执行。
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("before");
return null;
}
}
4.4 自定义初始化方法init回调
通过配置文件或注解对 Bean 的自定义初始化方法。bean的自定义初始化阶段,是指在bean的属性注入完成后,但在bean的初始化方法执行前,可以通过一些方式为bean添加一些自定义的操作,比如修改bean的属性,添加一些逻辑,或者代理bean的方法等。
- 通过配置文件初始化
<bean id="user" class="com.example.User" init-method="init">
<property name="name" value="张三"/>
<property name="age" value="18"/>
</bean>
public class User {
private String name;
private int age;
public void init() {
System.out.println("User bean is initialized");
}
}
- 实现InitializingBean接口,并重写afterPropertiesSet()方法。这个方法会在属性赋值后自动调用。
public class Student implements InitializingBean {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//重写初始化方法,打印学生的信息
@Override
public void afterPropertiesSet() {
System.out.println("Student: name = " + name + ", age = " + age);
}
}
- 使用@PostConstruct注解标注一个方法。这个方法也会在属性赋值后自动调用,且优先于afterPropertiesSet()方法。
@Component
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//使用@PostConstruct注解标记一个初始化方法,打印信息
@PostConstruct
public void init() {
System.out.println("Person: name = " + name + ", age = " + age);
}
}
4.5 BeanPostProcessor的after()方法回调
这个方法会在bean的初始化方法调用之后被Spring容器执行。这个方法的参数是bean对象和bean的名称,这个方法的返回值也是bean对象,你可以在这个方法中对bean对象进行一些处理,或者返回一个新的对象。
BeanPostProcessor的after()方法回调的作用是,让你可以在bean的初始化之后,对bean进行一些自定义的操作,比如修改bean的属性,添加一些逻辑,或者代理bean的方法等。你可以在一个容器中注册多个BeanPostProcessor的实现类,它们的after()方法回调会按照相同的顺序依次执行,你可以通过实现Ordered接口来控制执行顺序也可以通过@Ordered注解实现。
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor 的 postProcessorAfterInitialization 方法执行");
return null;
}
}
5. 使用阶段
初始化完成之后,Bean 这时候已经可以被 Spring 所使用了。这些 Bean 分以下几种情况
- 单例bean:这些bean只有一个实例,它们在容器启动时就被创建,并且在容器关闭时被销毁单例bean可以通过getBean()方法获取,也可以通过@Autowire注解注入到其他bean中。
- 多例bean:这些bean每次请求都会创建一个新的实例,它们不会被容器管理,也不会被销毁[。原型bean可以通过getBean()方法获取,也可以通过@Autowire注解注入到其他bean中,但是每次注入都会得到一个新的对象。
- 延迟加载bean:这些bean只有在第一次被请求时才会被创建,之后就和单例bean一样,只有一个实例,会被容器管理和销毁。延迟加载bean可以通过getBean()方法获取,也可以通过@Autowire注解注入到其他bean中。
- 工厂bean:这些bean不是直接创建对象,而是通过实现FactoryBean接口的getObject()方法,返回一个或多个对象的实例。工厂bean可以通过getBean()方法获取,也可以通过@Autowire注解注入到其他bean中,但是需要注意区分工厂bean本身和它创建的对象。
6. 销毁阶段
bean的销毁阶段是指当应用程序结束运行或者需要清理资源时,Spring容器会销毁所有不再需要的bean。需要注意的是,只有单例bean才会被Spring容器管理和销毁,多例bean不会被Spring容器管理和销毁,它们的生命周期由使用者自行控制。这个过程包括以下两个步骤。
- DisposableBean接口方法:如果bean实现了DisposableBean接口,那么在bean销毁前,Spring会自动调用其destroy方法,以便进行资源清理和自定义操作。
public class MyBean implements DisposableBean {
@Override
public void destroy() throws Exception {
// 在这里执行销毁操作
System.out.println("MyBean is being destroyed...");
}
}
-
自定义销毁方法:如果bean在配置文件中指定了destroy-method属性,或者在@Bean注解中指定了destroyMethod属性,或者在类中使用了@PreDestroy注解标记了一个方法,那么在bean销毁前,Spring会自动调用这些方法,以便进行资源清理和自定义操作。
- xml
<bean id="myBean" class="com.example.MyBean" destroy-method="destroyMethod"/>
public class MyBean { public void destroyMethod() { // 在这里执行销毁操作 System.out.println("MyBean is being destroyed..."); } }
- 注解
@Component
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//使用@PostConstruct注解标记一个销毁方法,打印信息
@PreDestroy
public void destroy() {
System.out.println("Person: name = " + name + ", age = " + age);
}
}