首页 > 其他分享 >[Spring]Bean生命周期

[Spring]Bean生命周期

时间:2024-08-12 21:16:06浏览次数:5  
标签:初始化 生命周期 mbd Spring beanName bean Object Bean null

image

生命周期的概要流程

Bean 的生命周期概括起来就是 4 个阶段:

  1. 实例化(Instantiation)
  2. 属性赋值(Populate)
  3. 初始化(Initialization)
  4. 销毁(Destruction)

image

实例化:第 1 步,实例化一个 bean 对象;
属性赋值:第 2 步,为 bean 设置相关属性和依赖;
初始化:第 3~7 步,步骤较多,其中第 5、6 步为初始化操作,第 3、4 步为在初始化前执行,第 7 步在初始化后执行,该阶段结束,才能被用户使用;
销毁:第 8~10步,第8步不是真正意义上的销毁(还没使用呢),而是先在使用前注册了销毁的相关调用接口,为了后面第9、10步真正销毁 bean 时再执行相应的方法。

下面我们结合代码来直观的看下,在 doCreateBean() 方法中能看到依次执行了这 4 个阶段:

// AbstractAutowireCapableBeanFactory.java
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
    throws BeanCreationException {

    // 1. 实例化
    BeanWrapper instanceWrapper = null;
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }

    Object exposedObject = bean;
    try {
        // 2. 属性赋值
        populateBean(beanName, mbd, instanceWrapper);
        // 3. 初始化
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }

    // 4. 销毁-注册回调接口
    try {
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }

    return exposedObject;
}

由于初始化包含了第 3~7步,较复杂,所以我们进到 initializeBean() 方法里具体看下其过程(注释的序号对应图中序号):

// AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    // 3. 检查 Aware 相关接口并设置相关依赖
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        invokeAwareMethods(beanName, bean);
    }

    // 4. BeanPostProcessor 前置处理
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    // 5. 若实现 InitializingBean 接口,调用 afterPropertiesSet() 方法
    // 6. 若配置自定义的 init-method方法,则执行
    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
    }
    // 7. BeanPostProceesor 后置处理
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

在 invokInitMethods() 方法中会检查 InitializingBean 接口和 init-method 方法,销毁的过程也与其类似:

// DisposableBeanAdapter.java
public void destroy() {
    // 9. 若实现 DisposableBean 接口,则执行 destory()方法
    if (this.invokeDisposableBean) {
        try {
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                    ((DisposableBean) this.bean).destroy();
                    return null;
                }, this.acc);
            }
            else {
                ((DisposableBean) this.bean).destroy();
            }
        }
    }

	// 10. 若配置自定义的 detory-method 方法,则执行
    if (this.destroyMethod != null) {
        invokeCustomDestroyMethod(this.destroyMethod);
    }
    else if (this.destroyMethodName != null) {
        Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
        if (methodToInvoke != null) {
            invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
        }
    }
}

从 Spring 的源码我们可以直观的看到其执行过程,而我们记忆其过程便可以从这 4 个阶段出发,实例化、属性赋值、初始化、销毁。其中细节较多的便是初始化,涉及了 Aware、BeanPostProcessor、InitializingBean、init-method 的概念。这些都是 Spring 提供的扩展点,其具体作用将在下一节讲述。

扩展点的作用

Aware 接口

若 Spring 检测到 bean 实现了 Aware 接口,则会为其注入相应的依赖。所以通过让bean 实现 Aware 接口,则能在 bean 中获得相应的 Spring 容器资源。
Spring 中提供的 Aware 接口有:

BeanNameAware:注入当前 bean 对应 beanName;
BeanClassLoaderAware:注入加载当前 bean 的 ClassLoader;
BeanFactoryAware:注入 当前BeanFactory容器 的引用。

其代码实现如下:

// AbstractAutowireCapableBeanFactory.java
private void invokeAwareMethods(final String beanName, final Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
        if (bean instanceof BeanClassLoaderAware) {
            ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
            
        }
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}

以上是针对 BeanFactory 类型的容器,而对于 ApplicationContext 类型的容器,也提供了 Aware 接口,只不过这些 Aware 接口的注入实现,是通过 BeanPostProcessor 的方式注入的,但其作用仍是注入依赖。

EnvironmentAware:注入 Enviroment,一般用于获取配置属性;
EmbeddedValueResolverAware:注入 EmbeddedValueResolver(Spring EL解析器),一般用于参数解析;
ApplicationContextAware(ResourceLoader、ApplicationEventPublisherAware、MessageSourceAware):注入 ApplicationContext 容器本身。

其代码实现如下:
代码解读复制代码// ApplicationContextAwareProcessor.java
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
}

if (bean instanceof EmbeddedValueResolverAware) {
    ((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}

if (bean instanceof ResourceLoaderAware) {
    ((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);
}

if (bean instanceof ApplicationEventPublisherAware) {
    ((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);
}

if (bean instanceof MessageSourceAware) {
    ((MessageSourceAware)bean).setMessageSource(this.applicationContext);
}

if (bean instanceof ApplicationContextAware) {
    ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
}

}

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;
	}

}

常用场景有:

对于标记接口的实现类,进行自定义处理。例如3.1节中所说的ApplicationContextAwareProcessor,为其注入相应依赖;再举个例子,自定义对实现解密接口的类,将对其属性进行解密处理;
为当前对象提供代理实现。例如 Spring AOP 功能,生成对象的代理类,然后返回。

代码解读复制代码// AbstractAutoProxyCreator.java
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
// 返回代理类
return proxy;
}

return null;

}
3.3 InitializingBean 和 init-method
InitializingBean 和 init-method 是 Spring 为 bean 初始化提供的扩展点。
InitializingBean接口 的定义如下:
代码解读复制代码public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
在 afterPropertiesSet() 方法写初始化逻辑。
指定 init-method 方法,指定初始化方法:
代码解读复制代码

<bean id="demo" class="com.chaycao.Demo" init-method="init()"/>
DisposableBean 和 destory-method 与上述类似,就不描述了。

总结

最后总结下如何记忆 Spring Bean 的生命周期:
首先是实例化、属性赋值、初始化、销毁这 4 个大阶段;
再是初始化的具体操作,有 Aware 接口的依赖注入、BeanPostProcessor 在初始化前后的处理以及 InitializingBean 和 init-method 的初始化操作;
销毁的具体操作,有注册相关销毁回调接口,最后通过DisposableBean 和 destory-method 进行销毁。

标签:初始化,生命周期,mbd,Spring,beanName,bean,Object,Bean,null
From: https://www.cnblogs.com/DCFV/p/18355755

相关文章

  • 报错:2024-08-12T18:39:35.313+08:00 ERROR 29668 --- [demo2] [ main] o.s.
    org.springframework.beans.factory.BeanDefinitionStoreException:Failedtoparseconfigurationclass[com.example.demo.DemoApplication]atorg.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:179)~[spring-con......
  • 【IDEA飘红】Could not autowire. No beans of 'OrderDao' type found.
     问题背景:SpringBoot框架下,MyBatis-Generator的插件生成了Dao.java、Bean.java、Mapper.xml,并且通过MapperScans注解把Dao层注入到Spring中。但是Dao层本身没有添加@Mapper注解或者@Component注解,导致IDEA无法识别Dao层为JavaBean,于是报错:Couldnotautowire.Nobeansof'O......
  • 微服务安全加固:Spring Cloud的细粒度权限控制策略
    标题:微服务安全加固:SpringCloud的细粒度权限控制策略在微服务架构中,服务的细粒度权限控制是保障系统安全的关键。SpringCloud作为一个微服务架构的解决方案集合,提供了多种工具和策略来实现这一目标。本文将详细介绍如何利用SpringCloud中的各种组件,如SpringCloudSecur......
  • springboot学生作业管理系统---附源码14916
    摘  要  在信息化社会中,人们需要针对性的信息获取途径。然而,由于不同角度和偏好的存在,人们经常只能获得特定类型的信息,这也是技术攻克难题之一。为了解决学生作业管理系统等问题,本研究通过分析和研究,设计开发了学生作业管理系统。学生作业管理系统主要功能模块包括系......
  • 使用orcale数据库的springboot项目打war包部署到tomcat后启动报错解决办法(缺少UCP数据
    我将在我本丢运行ok的springboot项目打成war包后部署到tomcat后,启动tomcat的时候一直显示:由于之前的错误,Context[/ruoyi]启动失败......,查看tomcat的日志文件发现报错:12-Aug-202410:20:35.183严重[main]org.apache.catalina.core.StandardContext.listenerStart配置应用......
  • SpringSecurity+前端项目+redis完成认证授权的代码
    1.前端准备工作--都在全局main.js页面中设置的1.1.创建Vue工程后,并导入elementui和axios,添加连接后端项目的路径,把axios挂载到Vue1.2.前置路由守卫(所有路由跳转前核实一下身份)//前置路由守卫--所有的路由跳转都先经过这里//to:即将要访问的路径from:从哪里来......
  • 基于SpringBoot+MySQL+SSM+Vue.js的物业管理系统(附论文)
    获取见最下方名片信息获取见最下方名片信息获取见最下方名片信息演示视频基于SpringBoot+MySQL+SSM+Vue.js的物业管理系统(附论文)技术描述开发工具:Idea/Eclipse数据库:MySQLJar包仓库:Maven前端框架:Vue/ElementUI后端框架:Spring+SpringMVC+Mybatis+Sprin......
  • Springboot计算机毕业设计公益捐赠管理系统r9m00
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表捐赠者,领取者,物品分类,物品捐赠,旧物展示,物品退还,物品领取,退还管理,回收管理,回收站,物品需求,在线捐赠,需求展示,在线聊天开题报告内容一、研究背景随着......
  • 基于SpringBoot+MySQL+SSM+Vue.js的大学生兼职系统(附论文)
    获取见最下方名片信息获取见最下方名片信息获取见最下方名片信息演示视频基于SpringBoot+MySQL+SSM+Vue.js的大学生兼职系统(附论文)技术描述开发工具:Idea/Eclipse数据库:MySQLJar包仓库:Maven前端框架:Vue/ElementUI后端框架:Spring+SpringMVC+Mybatis+Spr......
  • Springboot计算机毕业设计广金考研助力系统(程序+源码+数据库)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表学生,学长,学校百科,考研全知道,学长学姐说,身份认证,分类,寻研友,每日打卡开题报告内容一、研究背景与意义1.1研究背景随着社会的快速发展和高等教育的普及......