Spring Bean 的生命周期
一、bean的生命周期
- 实例化 Instantiation
- 属性赋值 Populate
- 初始化 Initialization
- 销毁 Destruction
实例化 -> 属性赋值 -> 初始化 -> 销毁
1.如果是单例 bean ,随着容器的创建而创建即实例化,多例bean是获取的时候实例化
2.属性注入
3.后处理器前置过程 即在初始化方法之前执行的 方法 postProcessBeforeInitialization
4.初始化方法
5.后处理器后置过程 即在初始化方法之后执行的 方法 postProcessAfterInitialization aop动态代理就在这一步
6.得到最终的 bean
7.销毁
二、bean自身的方法
构造函数、getter/setter 以及 init-method 和 destory-method 所指定的方法等,也就对应着上文说的实例化 -> 属性赋值 -> 初始化 -> 销毁四个阶段。
bean 的作用域:
- Singleton - 每个 Spring IoC 容器仅有一个单实例。
- Prototype - 每次请求都会产生一个新的实例。
- Request - 每一次 HTTP 请求都会产生一个新的实例,并且该 bean 仅在当前 HTTP 请求内有效。
- Session - 每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP session 内有效。
- Global-session - 类似于标准的 HTTP Session 作用域,不过它仅仅在基于 portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 portlet web 应用的各种不同的 portlet 所共享。在 global session 作用域中定义的 bean 被限定于全局 portlet Session 的生命周期范围内。如果你在 web 中使用 global session 作用域来标识 bean,那么 web 会自动当成 session 类型来使用。
仅当用户使用支持 Web 的 ApplicationContext 时,最后三个才可用。
三、Aware接口
可以理解为 Bean 类直接实现接口的方法,比如
BeanNameAware
、BeanFactoryAware
、ApplicationContextAware
、InitializingBean
、DisposableBean
等方法,例如,实现了BeanNameAware接口,重写setBeanName()方法,可以获得当前的bean的名字。
1,实例化bean对象,以及设置bean属性;
2,如果通过Aware接口声明了依赖关系,则会注入Bean对容器基础设施层面的依赖,Aware接口是为了感知到自身的一些属性。容器管理的Bean一般不需要知道容器的状态和直接使用容器。但是在某些情况下是需要在Bean中对IOC容器进行操作的。这时候需要在bean中设置对容器的感知。SpringIOC容器也提供了该功能,它是通过特定的Aware接口来完成的。 图中所示:
- BeanNameAware接口,可以知道自己在容器中的名字。
- BeanFactoryAware接口,有一个方法
setBeanFactory(BeanFactory beanFactory)
,用来获取当前环境中的 BeanFactory
。- ApplicationContextAware接口,有一个方法
setApplicationContext(ApplicationContext applicationContext)
,用来获取当前环境中的 ApplicationContext
。- 所有的 Aware 方法都是
在初始化阶段之前调用的
。3,紧接着会调用BeanPostProcess的前置初始化方法postProcessBeforeInitialization,主要作用是在Spring完成实例化之后,初始化之前,对Spring容器实例化的Bean添加自定义的处理逻辑。有点类似于AOP。
4,如果实现了BeanFactoryPostProcessor接口的afterPropertiesSet方法,做一些属性被设定后的自定义的事情。
5,调用Bean自身定义的init方法,去做一些初始化相关的工作。
6,调用BeanPostProcess的后置初始化方法,postProcessAfterInitialization去做一些bean初始化之后的自定义工作。
7,完成以上创建之后就可以在应用里使用这个Bean了。
四、BeanPostProcessor 一系列接口
BeanPostProcessor 一系列接口:
InstantiationAwareBeanPostProcessor
是 BeanPostProcessor 的子接口,常用的有如下三个方法:
postProcessBeforeInstantiation(Class beanClass, String beanName):在bean实例化之前调用,返回值:如果返回的不为null,那么后续的Bean的创建流程【实例化、初始化afterProperties】都不会执行,而是直接使用返回的快捷Bean
postProcessProperties(PropertyValues pvs, Object bean, String beanName):在bean实例化之后、设置属性前调用,返回值:如果返回null,那么将不会进行后续的属性填充,比如依赖注入等,如果返回的pvs额外的添加了属性,那么后续会填充到该类对应的属性中。
postProcessAfterInstantiation(Class beanClass, String beanName):在bean实例化之后调用,返回值:如果有指定的bean的时候返回false,那么后续的属性填充和属性依赖注入populateBean将不会执行,同时后续的postProcessPropertyValues将不会执行,但是初始化和BeanPostProcessor的仍然会执行。BeanPostProcessor
该接口有两个方法:
postProcessBeforeInitialization(Object bean, String beanName):在初始化之前调用此方法
postProcessAfterInitialization(Object bean, String beanName):在初始化之后调用此方法
五、代码
UserBean
package com.qf.test;
import org.springframework.beans.BeansException;
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;
import org.springframework.stereotype.Component;
/**
* @author HHy
* @date 2023/5/1
* @description UserBean
*/
@Component
public class UserBean implements BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean {
// id
private Integer id;
// 名字
private String name;
// 构造函数
public UserBean(Integer id, String name) {
this.id = id;
this.name = name;
System.out.println("构造函数");
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
System.out.println("属性注入id");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("属性注入name");
}
@Override
public void setBeanName(String name) {
System.out.println(name);
System.out.println("调用BeanNameAware.setBeanName()方法");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
UserBean user = applicationContext.getBean("user", UserBean.class);
System.out.println(user);
System.out.println("调用setApplicationContext方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("调用 InitializingBean.afterPropertiesSet() 方法");
}
public void myInit() {
System.out.println("init()");
}
@Override
public void destroy() throws Exception {
System.out.println("调用DisposableBean.destroy()");
}
public void myDestroy() {
System.out.println("myDestroy()");
}
@Override
public String toString() {
return "UserBean{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
MyInstantiationAwareBeanPostProcessor
package com.qf.test;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;
/**
* @author HHy
* @date 2023/5/7
* @desc MyInstantiationAwareBeanPostProcessor
*/
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if ("user".equals(beanName)) {
System.out.println("调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法");
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if ("user".equals(beanName)) {
UserBean userBean = (UserBean) bean;
System.out.println("调用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法");
System.out.println(userBean);
}
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if ("user".equals(beanName)) {
System.out.println("调用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法");
}
return null;
}
}
MyBeanPostProcessor
package com.qf.test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
/**
* @author HHy
* @date 2023/5/7
* @desc MyBeanPostProcessor
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("user".equals(beanName)) {
System.out.println("调用 BeanPostProcessor.postProcessBeforeInitialization() 方法");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("user".equals(beanName)) {
System.out.println("调用 BeanPostProcessor.postProcessAfterInitialization() 方法");
}
return bean;
}
}
bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.qf.test.UserBean" init-method="myInit" destroy-method="myDestroy">
<!-- 构造函数注入 -->
<constructor-arg name="id" value="1" /> <!-- 除标签名称有变化,其他均和Set注入一致 -->
<constructor-arg name="name" value="zs" />
<!-- setter方法注入 -->
<property name="id" value="2"/>
<property name="name" value="ls"/>
</bean>
<bean id="myBeanPostProcessor" class="com.qf.test.MyBeanPostProcessor"/>
</beans>
Test
package com.qf.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author HHy
* @date 2023/5/1
* @description SpringTest
*/
public class SpringTest {
@Test
public void Test() {
AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
UserBean user = applicationContext.getBean("user", UserBean.class);
applicationContext.close();
}
}
ription SpringTest
*/
public class SpringTest {
@Test
public void Test() {
AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
UserBean user = applicationContext.getBean("user", UserBean.class);
applicationContext.close();
}
}