Bean的生命周期 - 【Spring底层原理】

// 启动类

public class MainTest {

@Test

public void TestMain() {

// 创建IOC容器

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

// applicationContext.getBean(“dog”);

applicationContext.close();

}

}

// 待注入的Bean

public class Dog {

public Dog(){

System.out.println(“dog create”);

}

public void init(){

System.out.println(“dog init”);

}

public void destroy(){

System.out.println(“dog destroy”);

}

}

// 配置类

@Configuration

public class AppConfig {

// @Scope(“prototype”)

// 通过@Bean注解指定初始化和销毁方法

@Bean(initMethod = “init”,destroyMethod = “destroy”)

public Dog dog(){

return new Dog();

}

}

这是单实例场景下的案例,单实例是在容器启动的时候实例化对象,容器关闭的时候进行销毁,可以看到,通过@Bean(initMethod = "init",destroyMethod = "destroy"),可以指定初始化和销毁方法。

image-20210303151429684

如果是多实例,将配置类中的@Scope("prototype")放开,多实例是在获取对象的时候实例化对象,这时,直接运行启动类啥都不会打印,因为没有获取对象,也就没有初始化和销毁,因此需要将启动类中的applicationContext.getBean("dog");放开,获取对象,此时运行启动类,进行了创建Bean和初始化Bean,而销毁则当对象长时间不用且没有其他对象引用时,由Java垃圾回收器回收。

image-20210303152419553

【2】实现接口

将Bean对象实现InitializingBean, DisposableBean接口,重写destroy和afterPropertiesSet方法进行销毁和初始化,注意要@Component注解将Bean注入容器中,并在配置类中使用@ComponentScan注解进行扫描,以cat对象为例子:

// 启动类

@Test

public void TestMain() {

// 创建IOC容器

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

applicationContext.close();

}

// 待注入的Bean

@Component

public class Cat implements InitializingBean, DisposableBean {

public Cat(){

System.out.println(“cat create”);

}

// 销毁Bean

public void destroy() throws Exception {

System.out.println(“cat destroy”);

}

// 初始化Bean

public void afterPropertiesSet() throws Exception {

System.out.println(“cat afterPropertiesSet”);

}

}

// 配置类

@ComponentScan(“bean”)

@Configuration

public class AppConfig {

}

实现InitializingBean, DisposableBean接口,重写destroy和afterPropertiesSet方法进行销毁和初始化,可以看到进行初始化和销毁:

image-20210303154833409

【3】使用JSR250注解规范

使用JSR250注解规范,通过@PostConstruct注解和@PreDestroy注解进行对象的创建赋值调用和销毁对象,以pig对象为例:

// 启动类

@Test

public void TestMain() {

// 创建IOC容器

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

applicationContext.close();

}

// 待注入的Bean

@Component

public class Pig {

public Pig(){

System.out.println(“pig create”);

}

// @PostConstruct:对象创建并赋值之后调用

@PostConstruct

public void init(){

System.out.println(“pig postConstruct”);

}

// @PreDestroy:容器移除对象之前

@PreDestroy

public void destroy(){

System.out.println(“pig destroy”);

}

}

// 配置类

@ComponentScan(“bean”)

@Configuration

public class AppConfig {

}

使用@PostConstruct注解作用来初始化方法上面,@PreDestroy注解作用在销毁方法上面,运行启动类,可以看到进行初始化和销毁:

image-20210303163108716

【4】后置处理器

后置处理器是在Bean初始化前后进行一些处理工作,实现BeanPostProcessor类,重写方法,postProcessBeforeInitialization在初始化之前工作,postProcessAfterInitialization在初始化之后工作,在pig对象实例中添加:

@Component // 将后置处理器加入到容器中

public class MyBeanPostProcessor implements BeanPostProcessor {

// postProcessBeforeInitialization:在初始化之前工作

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

System.out.println(“postProcessBeforeInitialization” + beanName + “===” + bean);

return bean;

}

// postProcessAfterInitialization:在初始化之后工作

@Override

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

System.out.println(“postProcessAfterInitialization” + beanName + “===” + bean);

return bean;

}

}

在pig对象初始化前后执行相应的代码,运行结果如下:

image-20210303164448128

三、源码追踪

在spring源码中,BeanPostProcessor后置处理器是一个非常重要的类,我们来看看spring底层是如何实现Bean初始化的

【1】刷新容器

IOC容器构造器调用refresh方法刷新容器

public AnnotationConfigApplicationContext(String… basePackages) {

this();

this.scan(basePackages);

// 刷新容器

this.refresh();

}

【2】获取实例

调用refresh中的finishBeanFactoryInitialization方法初始化所有单实例对象

public void refresh() throws BeansException, IllegalStateException {

synchronized(this.startupShutdownMonitor) {

StartupStep contextRefresh = this.applicationStartup.start(“spring.context.refresh”);

this.prepareRefresh();

ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

this.prepareBeanFactory(beanFactory);

try {

this.postProcessBeanFactory(beanFactory);

StartupStep beanPostProcess = this.applicationStartup.start(“spring.context.beans.post-process”);

this.invokeBeanFactoryPostProcessors(beanFactory);

this.registerBeanPostProcessors(beanFactory);

beanPostProcess.end();

this.initMessageSource();

this.initApplicationEventMulticaster();

this.onRefresh();

this.registerListeners();

// 初始化所有单实例对象

this.finishBeanFactoryInitialization(beanFactory);

this.finishRefresh();

} catch (BeansException var10) {

if (this.logger.isWarnEnabled()) {

this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);

}

this.destroyBeans();

this.cancelRefresh(var10);

throw var10;

} finally {

this.resetCommonCaches();

contextRefresh.end();

}

}

}

  1. preInstantiateSingletons类中调用getBean方法

  2. 调用doGetBean

  3. 调用getSingleton获取单实例

  4. 如果获取不到则调用createBean创建实例

this.getBean(beanName);

public Object getBean(String name) throws BeansException {

return this.doGetBean(name, (Class)null, (Object[])null, false);

}

if (mbd.isSingleton()) {

// 获取单实例

sharedInstance = this.getSingleton(beanName, () -> {

try {

// 如果获取不到则调用createBean创建实例

return this.createBean(beanName, mbd, args);

} catch (BeansException var5) {

this.destroySingleton(beanName);

throw var5;

}

});

bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

}

// 创建实例

beanInstance = this.doCreateBean(beanName, mbdToUse, args);

【3】创建实例

如何创建的呢,我们继续看源码,追踪到doCreateBean类中的initializeBean方法,在这个方法之前有个populateBean方法

  • populateBean:为Bean属性赋值

  • initializeBean:相当于后置处理器的调用

try {

// 为Bean属性赋值

this.populateBean(beanName, mbd, instanceWrapper);

// 相当于后置处理器的调用

exposedObject = this.initializeBean(beanName, exposedObject, mbd);

} catch (Throwable var18) {

if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {

throw (BeanCreationException)var18;

}

throw new BeanCreationException(mbd.getResourceDescription(), beanName, “Initialization of bean failed”, var18);

}

调用initializeBean方法中的invokeInitMethods方法执行初始化方法,在上面提到的实现接口、使用注解、自定义初始化都是在这个方法中执行的,注意看这个方法的前后:

  • applyBeanPostProcessorsBeforeInitialization

  • applyBeanPostProcessorsAfterInitialization

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {

if (System.getSecurityManager() != null) {

AccessController.doPrivileged(() -> {

this.invokeAwareMethods(beanName, bean);

return null;

}, this.getAccessControlContext());

} else {

this.invokeAwareMethods(beanName, bean);

}

Object wrappedBean = bean;

if (mbd == null || !mbd.isSynthetic()) {

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-4fwX9FyL-1715618149707)]

[外链图片转存中…(img-tn5b0Ymq-1715618149707)]

[外链图片转存中…(img-KbU0tDCN-1715618149707)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值