Spring 源码(17)Spring Bean的创建过程(8)Bean的初始化
知识回顾
Bean的创建过程会经历getBean,doGetBean,createBean,doCreateBean,然后Bean的创建又会经历实例化,属性填充,初始化。
在实例化createInstance时大致可以分为三种方式进行实例化:
- 使用
Supplier进行实例化,通过BeanFactoryPostProcessor对BeanDefinition进行修改,增加一个Supplier属性,放置一个lambda表达式用于创建对象 - 使用
factory-method进行实例化- 使用实例工厂实例化
- 使用静态工厂实例化
- 使用构造器反射进行实例化
- 使用
SmartInstantiationAwareBeanPostProcessor解析构造器,然后反射实例化 - 使用无参构造器进行实例化
- 使用
在属性填充populateBean时大致可以分为4个步骤:
- 调用
InstantiationAwareBeanPostProcessor接口的after方法修改Bean的信息 - 自动装配,将解析的属性和属性值放入到
pvs变量中- 按
autowireByType自动装配 - 按
autowireByName自动装配
- 按
- 执行通过
CommonAnnotationBeanPostProcessor和AtowiredAnnotationBeanPostProcessor解析的注解,然后注入到字段上 - 对属性的值进行解析,解析
pvs, 会涉及到参数转换,spel表达式解析,引用类型,String类型,List类型,Map类型,Set类型,Properties类型的解析,属性编辑器的解析等。
接下来解读初始化阶段
bean的初始化
bean的初始化initializeBean方法,直接上源码:
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 执行Aware 方法
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 执行 BeanPostProcessor before 接口
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 执行 init-method 方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 执行BeanPostProcessor after 方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
源码逻辑也很简单,大概就分成了4步:
- 执行
Aware接口的方法invokeAwareMethods - 执行
BeanPostProcessor#postProcessBeforeInitialization - 执行初始化方法
- 执行
BeanPostProcessor#postProcessAfterInitialization
执行Aware接口的方法
点进去:
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
// 执行BeanNameAware
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
// 执行BeanClassLoaderAware
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
// 执行BeanFactoryAware
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
这里只执行了3个接口的方法,BeanNameAware,BeanClassLoaderAwre,BeanFactoryAware,在Spring容器中不止这些Aware接口,这里为什么只执行了三个Aware接口?
在Spring容器BeanFactory构造时,对这三个接口进行了忽略:
public AbstractAutowireCapableBeanFactory() {
super();
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
所以这里只执行了这三个Aware接口,这里忽略,实际上就是不然这些属性通过自动装配设置属性值,而是通过Spring自己的回调进行设置值。
另外我们在开始的准备BeanFactory的时候又进行了忽略Aware接口:
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
这6个接口在哪里执行的呢?在BeanFactory准备阶段注册了一个BeanPostProcessor的实现叫ApplicationContextAwareProcessor类,这个类的before方法中就进行了调用:
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
return bean;
}
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
// 执行Aware接口
invokeAwareInterfaces(bean);
}
return bean;
}
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);
}
}
为什么要分开处理呢?
个人认为主要是做了个区分而已,前面三个接口输入BeanFactory范畴,而这6个接口属于ApplicationContext范畴,只是进行了归类处理而已。
执行BPP的Before方法
代码比较简单,就是循环的执行了BPP的before接口,这里在执行的时候,实现上也执行了在Bean进行merge的时候解析的@PostConstruct注解。
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
// 执行初始化方法
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}
这个方法的实现类为InitDestroyAnnotationBeanPostProcessor
执行初始化方法
执行初始化方法的时候,会分为两步,一个是执行InitializingBean 的afterPropertiesSet方法,另一个是执行自定义的init-method方法
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
// 判断当前Bean是否是实现了InitializingBean
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 执行
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// 执行自定义的初始化方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
执行BPP的after接口
BPP的after主要是用来实现AOP的,所以这里简单介绍下,循环执行after方法的调用。
源码:
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
源码比较简单,就循环执行了方法的调用。
初始化就解读完了,Spring的Bean的创建也基本讲完,最终创建出来的Bean对象就会放入到一级缓存singletonObjects中。
Spring 源码(17)Spring Bean的创建过程(8)Bean的初始化的更多相关文章
- Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...
- Spring源码分析专题 —— IOC容器启动过程(上篇)
声明 1.建议先阅读<Spring源码分析专题 -- 阅读指引> 2.强烈建议阅读过程中要参照调用过程图,每篇都有其对应的调用过程图 3.写文不易,转载请标明出处 前言 关于 IOC 容器 ...
- 初探Spring源码之Spring Bean的生命周期
写在前面的话: 学无止境,写博客纯粹是一种乐趣而已,把自己理解的东西分享出去,不意味全是对的,欢迎指正! Spring 容器初始化过程做了什么? AnnotationConfigApplication ...
- Spring源码 17 IOC refresh方法12
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
- Spring源码解读Spring IOC原理
一.什么是Ioc/DI? IoC 容器:最主要是完成了完成对象的创建和依赖的管理注入等等. 先从我们自己设计这样一个视角来考虑: 所谓控制反转,就是把原先我们代码里面需要实现的对象创建.依赖的代码,反 ...
- Spring源码阅读-spring启动
web.xml web.xml中的spring容器配置 <listener> <listener-class>org.springframework.web.context.C ...
- Spring源码:Spring IoC容器加载过程(2)
Spring源码版本:4.3.23.RELEASE 一.加载XML配置 通过XML配置创建Spring,创建入口是使用org.springframework.context.support.Class ...
- 【Spring 源码】Spring 加载资源并装配对象的过程(XmlBeanDefinitionReader)
Spring 加载资源并装配对象过程 在Spring中对XML配置文件的解析从3.1版本开始不再推荐使用XmlBeanFactory而是使用XmlBeanDefinitionReader. Class ...
- Spring源码:Spring IoC容器加载过程(1)
Spring源码版本:4.3.23.RELEASE 一.加载过程概览 Spring容器加载过程可以在org.springframework.context.support.AbstractApplic ...
- spring源码解析——spring源码导入eclipse
一.前言 众所周知,spring的强大之处.几乎所有的企业级开发中,都使用了spring了.在日常的开发中,我们是否只知道spring的配置,以及简单的使用场景.对其实现的代码没有进行深入的了 ...
随机推荐
- jupyter notebook使用技巧
shift + tab 键可以查看对应源代码(注意:需要先将代码运行才能查看) Jupyter Notebook 的快捷键 Jupyter Notebook 有两种键盘输入模式:1.命令模式,键盘输入 ...
- C#通过LDAP访问目录服务
C#通过LDAP访问目录服务 本文介绍如何编写C#程序通过LDAP协议访问微软目录服务获得用户在目录中的属性信息.在开始部分先简单句介绍LDAP协议,然后是技术比较及实现部分. 目录 什么是LDAP? ...
- 简单vue项目脚手架
简单vue项目脚手架 github地址 使用技术栈 webpack(^2.6.1) webpack-dev-server(^2.4.5) vue(^2.3.3) vuex(^2.3.1) vue-ro ...
- 现代CSS进化史
英文:https://medium.com/actualize-...编译:缪斯 CSS一直被web开发者认为是最简单也是最难的一门奇葩语言.它的入门确实非常简单--你只需为元素定义好样式属性和值,看 ...
- H5本地存储:sessionStorage和localStorage
作者:心叶时间:2018-05-01 18:30 H5提供了二种非常好用的本地存储方法:sessionStorage和localStorage,下面分别介绍一下: 1.sessionStorage:保 ...
- SQLite实现数据库的储存2+SQLite数据库可视化工具SQLite Stadio
今日所学 SQLite实现数据库的储存 查看数据库的两种方法 Android 中 SQLite 数据库的查看 - woider - 博客园 SQLite Studio安装教程 [SQLite]可视化工 ...
- 在 M1 Mac 上开发 .NET MAUI (iOS)
在 M1 Mac 上开始使用 .NET MAUI 开发 (iOS) 的最简单方法. .NET 多平台应用程序 UI (.NET MAUI) 是一个跨平台框架,用于使用 C# 和 XAML 创建本机移动 ...
- typora简单使用手册
typora简单使用手册讲解`` 下载网站 网址:https://typoraio.cn/ 苹果电脑:https://typora.en.softonic.com/ 正版呢当然是收费 破解版自行百度 ...
- 异步任务-springboot
异步任务-springboot 异步:异步与同步相对,当一个异步过程调用发出后,调用者在没有得到结果之前,就可以继续执行后续操作.也就是说无论异步方法执行代码需要多长时间,跟主线程没有任何影响,主线程 ...
- MDL锁
mdl锁的主要作用是用来维护表元数据的一致性.在表上有活动事务的时候,不可以对表元数据进行修改操作. 如果没有MDL锁的保护,那么session2可以直接执行,并导致session1出错. MDL锁是 ...