Spring之Bean生命周期源码解析
1.启动接口介绍
具体的流程图:Spring扫描底层流程 | ProcessOn免费在线作图,在线流程图,在线思维导图 |
AnnotationConfigApplicationContext接口主要做了两件事情:1.scan 2.加载非懒加载的spring a.对象68和70行是java中的JFR机制,相当于查看69行代码执行的黑盒子(耗时,性能等)
b.ClassPathBeanDefinitionScanner接口主要是把扫描到的BeanDefinition注册到spring容器中
c.当有两个类通过component注解的时候,如果内容一致,那么是不会报错的,isCompatible->中newDefinition.getSource().equals(existingDefinition.getSource())会判断资源是不是一致,如果一致直接返回false,这样checkCandidate接口就不会添加新的bean
if (this.checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);this.registerBeanDefinition(definitionHolder, this.registry);
}
d.可以在resources添加spring.components
其中文件内容:com.zhouyu.service.UserService=org.springframeweork.stereotype.Colmponent
e.加载非懒加载的spring
this.refresh()->this.finishBeanFactoryInitialization(beanFactory)->beanFactory.preInstantiateSingletons()
f.SmartInitializingSingleton是在所有的非懒加载的单例Bean创建完成之后执行的代码
g.这样在getBean的时候会调用有参的构造函数,但是因为UserService是一个单例对象,在new AnnotationConfigApplicationConfig的时候就创建了,所以此处还是打印了0.
@Component
public class UserService {private OrderService orderService;public UserService() {System.out.println(0);}public UserService(OrderService orderService) {System.out.println(1);this.orderService = orderService;}public void test() {System.out.println("test");}
}
public class Test {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = (UserService) applicationContext.getBean("userService", new OrderService());userService.test();}
}
2.实例化前
当前BeanDefinition对应的类成功加载后,就可以实例化对象了,但是...
在Spring中,实例化对象之前,Spring提供了一个扩展点,允许用户来控制是否在某个或某些Bean实例化之前做一些启动动作。这个扩展点叫InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()。比如:
@Component
public class ZhouyuBeanPostProcessor implements InstantiationAwareBeanPostProcessor {@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {if ("userService".equals(beanName)) {System.out.println("实例化前");}return null;}
}
如上代码会导致,在userService这个Bean实例化前,会进行打印。
值得注意的是,postProcessBeforeInstantiation()是有返回值的,如果这么实现:
@Component
public class ZhouyuBeanPostProcessor implements InstantiationAwareBeanPostProcessor {@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {if ("userService".equals(beanName)) {System.out.println("实例化前");return new UserService();}return null;}
}
userService这个Bean,在实例化前会直接返回一个由我们所定义的UserService对象。如果是这样,表示不需要Spring来实例化了,并且后续的Spring依赖注入也不会进行了,会跳过一些步骤,直接执行初始化后这一步。具体的代码细节在:createBean->resolveBeforeInstantiation中
3.实例化
在这个步骤中就会根据BeanDefinition去创建一个对象了。
3.1 实例化后,属性初始化之前可以使用MergedBeanDefinitionPostProcessor接口,进行一些初始化的操作,可以调用初始化接口、属性填充···
【eg】
扩展:对于任何一个Bean的执行流程如下:
- InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
- 实例化
- MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()
- InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
- getResolvedAutowireMode属性赋值(spring自带的依赖注入)
- InstantiationAwareBeanPostProcessor.postProcessProperties()(解析spring自带的autowired)
- Aware对象
- BeanPostProcessor.postProcessBeforeInitialization(),(包括@PostConstruct方法)
- 初始化
- BeanPostProcessor.postProcessAfterInitialization()
- beans.xml中<context:annotation-config/>就是将AutowiredAnnotationBeanPostProcessor作为一个bean加入到了spring容器中,然后对所有的注解@Autowired进行解析
4.Bean的销毁过程(销毁只涉及单例,原型的不涉及销毁,因为每次都是使用的时候再创建,并且没有任何保存操作)
Bean的销毁过程是在spring容器的关闭过程中的。比如:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) context.getBean("userService");
userService.test();// 容器关闭
context.close();
在Bean创建过程中,在最后(初始化之后),有一个步骤会去判断当前创建的Bean是不是DisposableBean:
- 当前Bean是否实现了DisposableBean接口
- 或者,当前Bean是否实现了AutoCloseable接口
- BeanDefinition中是否指定了destroyMethod
- 调用DestructionAwareBeanPostProcessor.requiresDestruction(bean)进行判断
- ApplicationListenerDetector中直接使得ApplicationListener是DisposableBean
- InitDestroyAnnotationBeanPostProcessor中使得拥有@PreDestroy注解了的方法就是DisposableBean
- 把符合上述任意一个条件的Bean适配成DisposableBeanAdapter对象,并存入disposableBeans中(一个LinkedHashMap)
在Spring容器关闭过程时:
- 首先发布ContextClosedEvent事件
- 调用lifecycleProcessor的onCloese()方法
- 销毁单例Bean
- 遍历disposableBeans
- 把每个disposableBean从单例池中移除
- 调用disposableBean的destroy()
- 如果这个disposableBean还被其他Bean依赖了,那么也得销毁其他Bean
- 如果这个disposableBean还包含了inner beans,将这些Bean从单例池中移除掉 (inner bean参考Core Technologies)
- 清空manualSingletonNames,是一个Set,存的是用户手动注册的单例Bean的beanName
- 清空allBeanNamesByType,是一个Map,key是bean类型,value是该类型所有的beanName数组
- 清空singletonBeanNamesByType,和allBeanNamesByType类似,只不过只存了单例Bean
这里涉及到一个设计模式:适配器模式
在销毁时,Spring会找出实现了DisposableBean接口的Bean。
但是我们在定义一个Bean时,如果这个Bean实现了DisposableBean接口,或者实现了AutoCloseable接口,或者在BeanDefinition中指定了destroyMethodName,那么这个Bean都属于“DisposableBean”,这些Bean在容器关闭时都要调用相应的销毁方法。
所以,这里就需要进行适配,将实现了DisposableBean接口、或者AutoCloseable接口等适配成实现了DisposableBean接口,所以就用到了DisposableBeanAdapter。
会把实现了AutoCloseable接口的类封装成DisposableBeanAdapter,而DisposableBeanAdapter实现了DisposableBean接口。
Spring之Bean生命周期源码解析相关推荐
- 【Spring】Bean生命周期源码分析 总结
[Spring]Bean生命周期源码总结 1.案例验证 定义两个bean A,B 以及实现MyBeanFactoryProcess,MyBeanProcessor,MyInstantiationAwa ...
- spring源码分析02-spring生命周期源码解析
spring生命周期流程图: 1.spring扫描 Spring最重要的功能就是帮助程序员创建对象(也就是IOC),而启动Spring就是为创建Bean对象 做准备,所以我们先明白Spring到底是怎 ...
- Activity与调用线(三):Activity生命周期源码解析
前言 很高兴遇见你~ 欢迎阅读我的文章. 关于Activity生命周期的文章,网络上真的很多,有很多的博客也都讲得相当不错,可见Activity的重要性是非常高的.事实上,我猜测每个android开发 ...
- Spring AOP 增强器获取的源码解析
Spring AOP 增强器获取的源码解析 转载于:https://juejin.im/post/5c2b230ae51d45778a5cad3e
- Spring Boot 核心原理与源码解析 - 目录
准备重新写 SpringBoot 配置文件解析原理 , 先在这里把要写的内容记下来 Spring Boot 核心原理与源码解析 - 目录 1\何时解析\如何解析 application.propert ...
- spring注解方式整合Dubbo源码解析
系列文章目录 前言 本节我们的Dubbo源码版本基于2.6.x 在前一章我们的整合案例中,我们有几个比较关键的步骤: 在启动类上标注了@EnableDubbo注解 在provider类上面标注了@Se ...
- Spring源码深度解析(郝佳)-学习-Spring消息-整合RabbitMQ及源码解析
我们经常在Spring项目中或者Spring Boot项目中使用RabbitMQ,一般使用的时候,己经由前人将配置配置好了,我们只需要写一个注解或者调用一个消息发送或者接收消息的监听器即可,但是底 ...
- Spring源码深度解析(郝佳)-Spring 常用注解使用及源码解析
我们在看Spring Boot源码时,经常会看到一些配置类中使用了注解,本身配置类的逻辑就比较复杂了,再加上一些注解在里面,让我们阅读源码更加难解释了,因此,这篇博客主要对配置类上的一些注解的使用 ...
- 【Spring】- Bean生命周期
2019独角兽企业重金招聘Python工程师标准>>> Spring Bean的生命周期: bean对象实例化 属性注入 beanfactory ApplicationContext ...
- Spring中Bean生命周期、实例化与初始化
创建Bean的入口:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean. ...
最新文章
- mybatis 使用resultMap实现数据库的操作
- 【机器学习入门】(1) K近邻算法:原理、实例应用(红酒分类预测)附python完整代码及数据集
- 注入Attention,精度涨30%!谷歌发表最新多目标“动态抠图”模型
- Codeforces Round #698 (Div. 2) D. Nezzar and Board(一步步推出来,超级清晰,不猜结论,看不懂来打我 ~ 好题 )
- spring-boot的access日志格式修改
- 毕业后的五年拉开大家差距的原因在哪里
- 获取C#中方法的执行时间及其代码注入
- mysql数据库的系统操作基本操作
- ES6 class 技术点拾遗
- mysql--------常用命令
- 神经网络二分类输出概率,神经网络二分类预测
- 三维计算机学校,什么是三维虚拟校园系统?
- 八月实施:电动自行车3c认证,电动自行车CCC认证费用周期,办理电动自行车ccc认证机构
- ROS学习:launch文件编写
- oracle怎么开启安全审计,安全审计产品:一项一项教你测等保2.0——Oracle安全审计...
- iPhone开发技巧之调试 — 程序Crash后的调试技巧
- Electron应用-云桌面客户端
- 九、51单片机之直流电机驱动
- WinCC智能报表(代替热风炉岗位工手抄日志)
- 奋斗正当时|云畅科技2022财年启动会顺利召开
热门文章
- 乞讨网站,要饭网,个人要饭网,在线要饭网站;含socket 通信;双端支付源码 ;源码
- python打开360浏览器_使用python3.7 的pycharm selenium自动化测试中启动360浏览器、360极速浏览器的方法...
- 小米浏览器导出html,小米浏览器离线视频如何导出 小米浏览器离线视频导出教程...
- Mac数据库可视化工具,workbench完全替代Navicat和PowerDesigner,Oracle官方免费可视化工具workbench!!
- JS实现图片的懒加载
- 深入理解Tomcat 6和Tomcat7的区别
- mingw-w64-i686-toolchain
- 纯手工获取的WINDOWS 7 32位 SP1后续补丁集ver201509的官方下载地址
- C语言:编程打印图形
- win10命令提示符cd 不到指定路径的解决