🚀 优质资源分享 🚀
学习路线指引(点击解锁) | 知识定位 | 人群定位 |
---|---|---|
🧡 Python实战微信订餐小程序 🧡 |
进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
💛Python量化交易实战💛 |
入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
知识回顾
解析完
Bean
信息的合并,可以知道
Spring
在实例化
Bean
之后,属性填充前,对
Bean
进行了
Bean
的合并操作,这里的操作主要做了对
Bean
对象标记了
@Autowired
、
@Value
、
@Resource
、
@PostConstruct
、
@PreDestroy
注解的字段或者方法进行解析,主要涉及到类都是
BeanPostProcessor
的实现,可见
BeanPostProcessor
接口的重要性。
这里再次回顾下
BeanPostProcessor
接口有哪些子接口:
-
InstantiationAwareBeanPostProcessor
Spring
给机会提前进行实例化,可用通过代理进行对象的创建
-
SmartInstantiationAwareBeanPostProcessor
用于预测
Bean
的类型,决定
Bean
的构造函数,用于实例化
-
MergedBeanDefinitionPostProcessor
用于合并
Bean
的信息,即解析Bean对象方法上或者字段上标记的注解,比如
@Resource
、
@Autowired
、
@PostConstruct
等。
-
DestructionAwareBeanPostProcessor
用于销毁
Bean
时调用的,比如执行标有
@PreDestroy
注解的方法
这些子接口的实现类比较多,比如:
-
AutowiredAnnotationBeanPostProcessor
-
ComonAnnotationBeanPostProcessor
-
InitDestroyAnnotationBeanPostProcessor
-
AnnotationAwareAspectJAutoProxyCreator
-
ScheduledAnnotationBeanPostProcessor
当然还不止这里列出来的,还有其他的就不列了,接下来分析
Spring
源码接下来做了什么?
对象的提前暴露
看源码:
// 省略代码....
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 提前暴露对象,用于解决循环依赖
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 添加一个lambda表达式到三级缓存中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
// 省略代码....
源码这里就添加了一个
lambda
表达式到一个
Map
中,然后结束了,并且明确说明了提前暴露是为了解决循环依赖问题。
什么是循环依赖?
循环依赖顾名思义,就是你中有我,我中有你,打个比方现在有个对象
A
,他有个属性
b
,这个属性b是对象
B
的,然后对象
B
中有个属性
a
,属性
a
是对象
A
的。
现在开始创建对象,按照
Spring
的标准创建流程
getBean
–>
doGetBean
–>
createBean
–>
doCreateBean
,先实例化,然后属性填充,然后执行
aware
方法,然后执行
BeanPostProcessor
的
before
方法,然后执行
init-method
,然后执行
BeanPostProcessor
的
after
方法。那么在执行属性填充时必然会去查找
a
或者
b
属性对应的对象,如果找不到就会去创建,那么就会出现下图的样子:
这样必然就出现了循环依赖,你我紧紧相拥,不想放开,死也要在一起的情形。
那么
Spring
为什么解决循环依赖需要进行提前暴露对象呢?
Spring
所以这个问题就很简单了,我们都知道
Bean
的创建是将实例化和初始化分开的,实例化之后的对象在
JVM
堆中已经开辟了内存空间地址,这个地址是不会变的,除非山崩地裂,海枯石烂,也就是应用重启了。
因此可以将已经实例化的对象放在另外一个
Map
中,一般来说都称之为半成品,当填充属性时,可以将先设置半成品对象,等到对象创建完之后在将半成品换成成品,这样的话对象进行属性填充时就可以直接先使用半成品填充,等到开始初始化时再将对象创建出来即可。
这样看来循环依赖只需要二级缓存就够了,但是在
Spring
中,存在一种特殊的对象,就是代理对象。也就是说在放入的半成品我们现在多了一种对象,那就是代理对象,这个时候就会出现使用代理对象还是普通对象呢?所以干脆在搞一个
Map
专门存放代理对象,这样就区分出来了,然后在使用的时候先判断下我们创建的对象是需要代理还是不需要代理,如果需要代理,那么就创建一个代理对象放在
map
中,否则直接使用普通对象就可以了。
Spring中的实现方式
Spring
是怎么处理的呢?
Spring
是将所有的对象都放在三级缓存中,也就是
lambda
表达式中:
// 添加一个lambda表达式到三级缓存中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
// 判断一级缓存中是否存在
if (!this.singletonObjects.containsKey(beanName)) {
// 没有就放入三级缓存中
this.singletonFactories.put(beanName, singletonFactory);
// 清空二级缓存
this.earlySingletonObjects.remove(beanName);
// 添加到已经注册的单例集合中
this.registeredSingletons.add(beanName);
}
}
}
在属性填充的时候,会执行到
getBean
,然后从缓存中获取
getSingleton
:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
// 从一级缓存中获取bean实例
Object singletonObject = this.singletonObjects.get(beanName);
// 如果一级缓存中没有数据并且没有正在创建的Bean直接返回
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 如果有正在创建的Bean,那么冲二级缓存中获取,早期的单例对象
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
// 二次检查一级缓存中是否有单例对象
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 二次判断二级缓存中是否存在单例对象
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 从三级缓存中获取Bean
ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 如果三级缓存中 单例工厂中有对象,那么就将该对象放在二级缓存中,并且清掉三级缓存
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
在获取单例对象时,会执行到三级缓存,然后执行
getObject
方法,最终就会触发
getEarlyBeanReference
方法的调用:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
// 添加 三级缓存,判断是否需要进行代理创建对象,是一个动态代理创建的代理对象
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
这里会判断,如果这个
BeanDefinition
是否满足条件,如果不满足,那么直接返回了,否则就会执行到
for
循环中的代码,而
getEarlyBeanReference
方法在
Spring
中只有
AbstractAutoProxyCreator
类进行了实质的实现:
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 早期代理对象的引用集合
this.earlyProxyReferences.put(cacheKey, bean);
// 创建代理
return wrapIfNecessary(bean, beanName, cacheKey);
}
点进去:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理对象
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
首先进行了判断,如果不满足创建代理的条件,都是直接返回这个对象,否则进入创建代理的方法,创建出代理对象,最终放入缓存中。点入到最后会发现使用了两种代理创建方式:
源码中的提前暴露对象牵扯出很多东西,循环依赖,三级缓存,aop等,这里解析了个大概,接下来继续主流程中的属性填充
populaeBean
方法。