Spring 核心
@Configuration
@Configuration 注解底层是如何实现的,通过源码咱们可以反推并总结为以下几点:
Spring 首先会获取到所有的 beandefenition
ConfigurationClassUtils 类中 checkConfigurationClassCandidate 方法判断是 Full @Configuration 还是 lite @Bean mode
通过 ConfigurationClassPostProcessor 后置处理器遍历所有的 beandefenition
将标记了 Full @Configuration 模式的 beandefenition,会对这个类进行 cglib 代理,生成一个代理类,并把这个类设置到 BeanDefenition 的 Class 属性中
配置类会被 CGLIB 增强 (生成代理对象),放进 IoC 容器内的是代理
对于内部类是没有限制的:可以是 Full 模式或者 Lite 模式
配置类内部可以通过方法调用来处理依赖,并且能够保证是同一个实例,都指向 IoC 内的那个单例
需要用这个 Bean 实例的时候,从这个 Class 属性中拿到的 Class 对象进行反射,最终反射出来的是代理增强后的类
通过 @Configuration 标注类的 Bean,Spring 会先去容器中查看是否有这个 Bean 实例,如果有就返回已有的对象,没有就创建一个,然后放到容器中
IOC 加载原理
详细可参考源码理解(源码分析 2 容器的基本实现、3 默认标签的解析、5 bean 的加载 小节有详细代码分析步骤)
也可根据如上入口 DEBUG 加深理解,以下是一些步骤说明:
new AnnotationConfigApplicationContext()
将配置、注解的信息读取,加载为 BeanDefinition 对象,这些信息包括 Bean 的类名、属性、构造函数参数等
注意 AnnotationConfigApplicationContext 该步骤的代码,也在 AbstractApplicationContext.invokeBeanFactoryPostProcessors 子逻辑块里面
注册 BeanDefinition 到 DefaultListableBeanFactory.beanDefinitionMap 中 (bean 为定义态)
XmlBeanFactory 注册方法 BeanDefinitionReaderUtils.registerBeanDefinition ()
AnnotationConfigApplicationContext 注册方法在 AbstractApplicationContext.refresh () 里面的 invokeBeanFactoryPostProcessors (beanFactory) 中,实际注册代码就比较深了,略
循环通过 BeanFactory.getBean () 创建 Bean (注意是非懒加载的,可以看 AbstractApplicationContext.getBean () 方法源码)
进入 AbstractBeanFactory.doGetBean 获取 Bean。这里会出现经典的循环依赖问题,后续详细介绍
DefaultSingletonBeanRegistry.singletonObjects (bean 为成熟态) 中获取,拿到则直接返回,结束 5 步骤,拿不到进入 5.2
实例化 Bean (反射,属性值都为空,纯净态)
依赖注入。循环依赖问题:如果此时 A 依赖 B,B 依赖 A,则 getBean (A) 会调用 getBean (B) 且 getBean (B) 又会调用 getBean (A)
初始化。进行方法回调,如 @PostConstruct 进行初始化,注意这里在依赖注入后,已经可以拿到依赖注入的对象了。可以在这里进行数据库连接池、线程池的初始化的业务逻辑
创建动态代理对象。BeanPostProcessor.postProcessAfterInitialization 里面创建了动态代理
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))
触发,对应源码AbstractAutoProxyCreator.wrapIfNecessary
的createProxy
代码块动态代理对象放入 DefaultSingletonBeanRegistry.singletonObjects 中
对比可以理解如下问题,如
Spring 国际化在哪一步处理 (AbstractApplicationContext.initMessageSource)
ApplicationContext 和 BeanFactory 区别
都是容器,是父子关系
ApplicationContext 提供上层程序员用的,功能更加全面,如事件监听、多语言等
BeanFactory 在底层真正干活的
Bean 的生命周期
可以参考源码分析部分 5 bean 的加载
理解。以下是核心步骤。未做额外说明,则都在 AbstractAutowireCapableBeanFactory 类中。
实例化,可以拆为两步说
推断构造方法
实例化
Bean 属性注入,详见 populateBean ()
初始化,对应代码为 initializeBean,相关步骤如下:
Aware 相关处理
invokeAwareMethods
((BeanNameAware) bean).setBeanName(beanName)
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl)
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this)
调用 BeanPostProcessor 的预初始化方法
applyBeanPostProcessorsBeforeInitialization
,@PostConstruct 也是初始化前处理调用初始化方法
invokeInitMethods
调用 InitializingBean 初始化方法
((InitializingBean) bean).afterPropertiesSet()
调用自定义初始化方法
invokeCustomInitMethod(beanName, bean, mbd)
调用 BeanPostProcessor 的初始化后方法
applyBeanPostProcessorsAfterInitialization
Bean 可以使用了,通过
DefaultSingletonBeanRegistry.getSingleton
添加普通对象或代理对象到容器中容器关闭
调用 DisposableBean.destroy ()。
DestructionAwareBeanPostProcessor.postProcessBeforeDestruction
被调用调用自定义销毁方法,没找到代码入口,可以参考
DisposableBeanAdapter.destroy()
代码理解
实例化
实例化代码可以从 AbstractBeanFactory.doGetBean
里面的 AbstractAutowireCapableBeanFactory.createBean
方法开始跟踪
准备工作
获取子类和父类已经合并的 RootBeanDefinition
详见 AbstractBeanFactory.doGetBean 的 RootBeanDefinition mbd = getMergedLocalBeanDefinition (beanName)
实例化
如下链路可以找到
BeanUtils.instantiateClass
的ctor.newInstance(argsWithDefaultValues)
,即反射加载代码链路如下
1.2.1 AbstractAutowireCapableBeanFactory.createBean
1.2.2 AbstractAutowireCapableBeanFactory.doCreateBean
1.2.3 AbstractAutowireCapableBeanFactory.createBeanInstance
1.2.4 AbstractAutowireCapableBeanFactory.instantiateBean
1.2.5 AbstractAutowireCapableBeanFactory.autowireConstructor。推断构造方法
1.2.6 SimpleInstantiationStrategy.instantiate
1.2.7 BeanUtilseanUtils.instantiateClass(constructorToUse)
如果是非普通对象,则会将代理对象创建,见 getEarlyBeanReference(beanName, mbd, bean))
推断构造方法
Spring 之推断构造方法底层原理详解
实例化 SimpleInstantiationStrategy.createBeanInstance 里面有推断构造方法底层源码
有点复杂,可以看文章理解 Spring 源码篇之推断构造方法 open in new window
优先级处理
对应源码在 AbstractApplicationContext.refresh () 进去,找到 AbstractApplicationContext.registerBeanPostProcessors ()
加载顺序如下:
先注册 @PriorityOrdered 的 Bean
再注册 @Ordered 的 Bean
后注册其他 Bean
这篇文章有图,结合源码理解也挺好,Spring Bean 的完整生命周期(带流程图,好记)open in new window
额外有些内容补充如下
Autowired、和构造方法注入是先根据 byType,再根据 byName 注入对象
对应原理参考 透过 Spring 源码解析注解 @Autowired、@Resource 的区别 open in new window。
循环依赖
手写循环依赖简单代码,我们用一级缓存解决了循环依赖 (仅限死循环问题,Spring 处理场景更复杂)
SimCircularCtxMainopen in new window
Spring 如何利用多级缓存解决循环依赖
用了 3 个 Map 即 3 级缓存处理
1 级缓存 singletonObjects
2 级缓存 earlySingletonObjects
3 级缓存 singletonFactory
首先尝试从 singletonObjects 里面获取实例,如果获取不到再从 earlySingletonObjects 里面获取
如果还获取不到,再尝试从 singletonFactories 里面获取 beanName 对应的 ObjectFactory
然后调用这个 ObjectFactory 的 getObject 来创建 bean,并放到 earlySingletonObjects 里面去,并且从 singletonFactories 里面 remove 掉这个 ObjectFactory (1、2 级缓存互斥,原因大概率是因为初始化完成后生成了代理)
一级缓存缓存完全体的 bean 对象
二级缓存是解决并发环境下锁性能问题
三级缓存是解决 AOP 问题,以及循环依赖问题。保证了二级缓存 getEarlySingletonObjects 获取的也是 AOP 代理对象,这样就和一级缓存对象对应上了。注意预期只有循环依赖的 bean 才进行动态代理,普通的 bean 依然在初始化后才去创建动态代理,这块逻辑对应 AbstractAutoProxyCreator.earlyProxyReferences
代码控制
三级缓存见示例代码 SimCircular3Ctxopen in new window
三级缓存示例代码如下
Spring 二级缓存能否解决循环依赖
可以,但是就是实例化之后,就要立即创建 AOP 代理了
另外注意下以下一些点
一级缓存其实就可以解决死循环依赖问题了,但是在多线程环境下要加如 synchronized 锁保证线程安全
二级缓存是在并发环境下解决锁粒度问题 (容器设置为懒加载就会有并发加载的问题)
Spring 的单例如何保证线程安全
用的双重检查锁保证,参考 Demo 理解 SimCircular2Ctxopen in new window
Spring 是否解决多例 Bean 的循环依赖
无法解决
如果是原型 bean,那么就意味着每次都要去创建对象,无法利用缓存,缓存只能在实例化后判断处理
Spring 是否解决构造函数中的循环依赖
无法解决
如果是构造方法注入,那么就意味着需要调用构造方法注入,也无法利用缓存,缓存只能在实例化后判断处理
评论区