论 spring 的三级缓存
预备知识
bean的生命周期
bean 的生命周期
为何会出现循环引用
这个问题只是出现在spring 容器的机制中,其实我们代码中很简单就解决了。
假设A 对象里需要注入一个B属性,B 对象里面需要注入一个A 属性。根据Bean 的生命周期,先实例化A 的实例,然后进行A属性的填充,这时就需要一个B的对象,在通过 beanFactory.getBean(B) 进行B对象的获取,同样,先进行B的实例化,之后进行B中A属性的复制,也会去调用beanFactory.getBean(A),进行获取,但是A变量还没有创建完成,singletonObjects变量池中没有,所以就行程了循环引用,为了解决这个问题就是A实例化之后,想找一个变量进行存储,后面有变量的创建需要用到她的话,直接使用这个变量的对象,earlySingletonObjects ,这样就解决了循环依赖的问题。
伪代码如下:
//伪代码就是这个意思
static class A {
private B b;
public void setB(B b) {
this.b = b;
}
}
static class B {
private A a;
public void setA(A a) {
this.a = a;
}
}
public static void main(String[] args) {
A earlySingletonObjects = new A();
B b;
{
b = new B();
b.setA(earlySingletonObjects);
}
earlySingletonObjects.setB(b);
A a = earlySingletonObjects;
// TODO: use a use b
}
不用三级缓存行不行
首先提出一个观点,不用三级缓存,使用两级缓存行不行,答案是肯定的,没问题,spring 为什么要使用三个变量池呢,我想是这样分类更明确。
说道分类明确,大家不禁有疑问,为什么这么说呢,是因为 假设 A 和B 之间进行循环引用,并且我们对A 进行了切面增强逻辑,如果我们只是将A的实例对象提前暴露出去是错误的,因为B中我们真正想使用的是A增强后的对象。好了,问题说清楚了,那用两个变量行不行,当然行了,创建A 的时候我们在进行属性赋值的时候,直接创建一个包含A 的代理对象,并将代理对象放入earlySingletonObjects 提前暴露变量池中,不就ok了吗,等到B使用的时候直接拿到A的代理对象,没有任何问题。所以我个人认为spring 在弄出一个singletonFactories 单纯就是解耦。
三级缓存,不 ,是三个变量
分别存储在 这三个变量当中.
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
三个对象的赋值过程
过程详解
代码如下:
- org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
}
- org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
Object sharedInstance = getSingleton(beanName);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
- org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
singletonObject = singletonFactory.getObject();
newSingleton = true;
if (newSingleton) {
//该方法
addSingleton(beanName, singletonObject);
}
return singletonObject;
}
}
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
扩展出aop 代理对象如何创建
首先我们开启aspectj的注解会给容器注册一个 BeanPostProcessor class name 为 AnnotationAwareAspectJAutoProxyCreator
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
}
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
AnnotationAwareAspectJAutoProxyCreator 的继承结构如下:
那么在什么时机去创建代理呢? 有两个时机,第一个是允许提前暴露的话,在实例化好目标对象之后,提前暴露给singletonFactories 当中时,使用getEarlyBeanReference 方法进行动态代理的替换
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
//使用getEarlyBeanReference 方法进行动态代理的替换
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
return exposedObject;
}
getEarlyBeanReference 所做的内容,会调用所有的SmartInstantiationAwareBeanPostProcessor 的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;
}
此时创建代理对象
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
剩下得流程该对目标对象属性赋值就赋值,该初始化初始化。一切照旧,只不过我们提前暴露的是 代理对象.
而after 做的是将为提前暴露的对象在代理一次
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
关于spring aop的源码分析,可以参看:文章来源:https://www.toymoban.com/news/detail-447706.html
<<spring技术内幕>>文章来源地址https://www.toymoban.com/news/detail-447706.html
到了这里,关于论 spring 的三级缓存的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!