目录
什么是 Spring Bean 的生命周期?
对于普通的 Java 对象,当 new 的时候创建对象,然后该对象就能够使用了。一旦该对象不再被使用,则由 Java 自动进行垃圾回收。
而 Spring 中的对象是 bean,bean 和普通的 Java 对象没啥大的区别,只不过 Spring 不再自己去 new 对象了,而是由 IoC 容器去帮助我们实例化对象并且管理它,我们需要哪个对象,去问 IoC 容器要即可。IoC 其实就是解决对象之间的耦合问题,Spring Bean 的生命周期完全由容器控制。
我们说的 Spring Bean 的生命周期主要指的是 singleton bean,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。
那么Spring 中的 bean 的作用域有哪些?
singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
prototype : 每次请求都会创建一个新的 bean 实例。
request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
global-session: 全局 session 作用域,仅仅在基于 Portlet 的 web 应用中才有意义,Spring5 已经没有了。Portlet 是能够生成语义代码(例如:HTML)片段的小型 Java Web 插件。它们基于 portlet 容器,可以像 servlet 一样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。
Bean 的生命周期概括起来就是 4 个阶段:
- 实例化(Instantiation)
- 属性赋值(Populate)
- 初始化(Initialization)
- 销毁(Destruction)
实例化:第 1 步,实例化一个 bean 对象;
属性赋值:第 2 步,为 bean 设置相关属性和依赖;
初始化:第 3~7 步,步骤较多,其中第 5、6 步为初始化操作,第 3、4 步为在初始化前执行,第 7 步在初始化后执行,该阶段结束,bean对象才能被用户使用;
销毁:第 8~10步,第8步不是真正意义上的销毁(还没使用呢),而是先在使用前注册了销毁的相关调用接口,为了后面第9、10步真正销毁 bean 时再执行相应的方法。
shift+shift 搜索 AbstractAutowireCapableBeanFactory ,查看创建bean的方法 doCreateBean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 实例化阶段
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
...
Object exposedObject = bean;
try {
// 属性赋值阶段
this.populateBean(beanName, mbd, instanceWrapper);
// 初始化阶段
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
} catch (Throwable var18) {
...
}
...
try {
//销毁化阶段
this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
} catch (BeanDefinitionValidationException var16) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
}
}
这里追踪初始化阶段方法的实现,先点进initializeBean()方法。
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
//3.检查aware接口,并配置相关依赖
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(() -> {
this.invokeAwareMethods(beanName, bean);
return null;
}, this.getAccessControlContext());
} else {
this.invokeAwareMethods(beanName, bean);
}
//4.BeanPostProcessor 前置处理器
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
}
//5.若实现 InitializingBean 接口,调用 afterPropertiesSet()方法
//6.若配置自定义的Init方法,则执行
try {
this.invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable var6) {
throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
}
//7.BeanPostProcessor 后置处理器
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
点进invokeAwareMethods()方法查看第三步是怎么实现的
private void invokeAwareMethods(String beanName, Object bean) {
//如果bean实现了Aware接口
if (bean instanceof Aware) {
//接口1
if (bean instanceof BeanNameAware) {
((BeanNameAware)bean).setBeanName(beanName);
}
//接口2
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = this.getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware)bean).setBeanClassLoader(bcl);
}
}
//接口3
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware)bean).setBeanFactory(this);
}
}
}
点进invokeInitMethods()方法查看源码,查看5、6步骤的实现
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
//5.若实现 InitializingBean 接口,调用 afterPropertiesSet()方法
boolean isInitializingBean = bean instanceof InitializingBean;
if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(() -> {
((InitializingBean)bean).afterPropertiesSet();
return null;
}, this.getAccessControlContext());
} catch (PrivilegedActionException var6) {
throw var6.getException();
}
} else {
((InitializingBean)bean).afterPropertiesSet();
}
}
//6.若配置自定义的Init方法,则执行
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) && (!isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
this.invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
其他流程的具体实现大家可以自己去追踪源码,这里就不详细追踪了。
总之我们从 Spring 的源码中可以直观的看到其执行过程,而我们记忆其过程便可以从这 4 个阶段出发,实例化、属性赋值、初始化、销毁。其中细节较多的便是初始化,涉及了 Aware、BeanPostProcessor、InitializingBean、init-method 的概念。这些都是 Spring 提供的扩展点
Spring中的扩展点
1.Aware 接口
若 Spring 检测到 bean 实现了 Aware 接口,则会为其注入相应的依赖。所以通过让bean 实现 Aware 接口,则能在 bean 中获得相应的 Spring 容器资源。
Spring 中提供的 Aware 接口有:
1.BeanNameAware:注入当前 bean 对应 beanName;
2.BeanClassLoaderAware:注入加载当前 bean 的 ClassLoader;
3.BeanFactoryAware:注入当前BeanFactory容器 的引用。
代码实现:
AbstractAutowireCapableBeanFactory.java
private void invokeAwareMethods(String beanName, Object bean) {
//如果bean实现了Aware接口
if (bean instanceof Aware) {
//接口1
if (bean instanceof BeanNameAware) {
((BeanNameAware)bean).setBeanName(beanName);
}
//接口2
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = this.getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware)bean).setBeanClassLoader(bcl);
}
}
//接口3
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware)bean).setBeanFactory(this);
}
}
}
BeanPostProcessor
BeanPostProcessor 是 Spring 为修改 bean提供的强大扩展点,其可作用于容器中所有 bean,其定义如下:
public interface BeanPostProcessor {
// 初始化前置处理
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
// 初始化后置处理
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
常用场景有:
1.对于标记接口的实现类,进行自定义处理
2.为当前对象提供代理实现。例如 Spring AOP 功能,生成对象的代理类,然后返回。
代码:AbstractAutoProxyCreator.java
//前置处理器
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = this.getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (this.isInfrastructureClass(beanClass) || this.shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = this.createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
} else {
return null;
}
}
InitializingBean 和 init-method
InitializingBean 和 init-method 是 Spring 为 bean 初始化提供的扩展点。
InitializingBean接口 的定义如下:
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
当 Spring 容器创建 Bean 实例后,会检测是否实现了 InitializingBean 接口,如果实现了,则会自动调用 afterPropertiesSet() 方法,执行初始化逻辑。
通过 @Bean 注解的 initMethod 属性来定义 Bean 的初始化方法。具体来说,你可以在 @Bean 注解中使用 initMethod 属性指定一个方法作为 Bean 的初始化方法。该方法会在 Bean 实例化后自动调用,执行初始化逻辑。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public MyBean myBean() {
return new MyBean();
}
}
public class MyBean {
public void init() {
// 在这里实现 Bean 的初始化逻辑
System.out.println("MyBean 初始化完成");
}
}
总结
实例化
1.Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
设置属性
2.Bean实例化后对将Bean的引入和值注入到Bean的属性中
初始化
3.如果Bean实现了BeanNameAware接口,注入当前 bean 对应 beanName;如果Bean实现了BeanClassLoaderAware接口,注入加载当前 bean 的 ClassLoader;如果Bean实现了BeanFactoryAware接口,注入当前BeanFactory容器 的引用。
4.如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
5.如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。
6.如果bean使用init-method声明了初始化方法,该方法也会被调用
7.如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
为销毁做准备
8.注册Destruction相关的回调接口,为后续的销毁做准备
使用
此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
销毁
9.如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法
10.如果bean使用了destory-method 声明销毁方法,该方法也会被调用。