前言
循环依赖,一直是一个令人头疼的问题。虽然我们一般情况下会尽量避免这种情况的发生,但很多时候它会在无意识的情况下出现。比如隔了好几个bean之后,发现循环起来了。那么什么是循环依赖呢?其实就是A依赖B,但B又依赖A。或者A依赖B,B依赖C,C又依赖A这样,构成一个循环。按照我们之前的实现,是无法解决这种循环的。因为之前的逻辑实际上比较单纯,就是遍历Bean定义,然后逐一实例化,遇到依赖的Bean,那就先去实例化依赖Bean。但这样就会发现,实例依赖Bean的时候,依赖Bean又依赖当前Bean。这样就一直循环下去,最后StackOverFlow。那么Spring是怎么解决这个问题的呢?答案是利用三级缓存。三级缓存分别存放不同阶段的Bean,这样,我们在依赖时,就可以去依赖一个暂时还没有构建完成的Bean,就避免了死循环下去的情况。
工程结构
├─src
│ ├─main
│ │ ├─java
│ │ │ └─com
│ │ │ └─akitsuki
│ │ │ └─springframework
│ │ │ ├─aop
│ │ │ │ │ AdvisedSupport.java
│ │ │ │ │ Advisor.java
│ │ │ │ │ BeforeAdvice.java
│ │ │ │ │ ClassFilter.java
│ │ │ │ │ MethodBeforeAdvice.java
│ │ │ │ │ MethodMatcher.java
│ │ │ │ │ Pointcut.java
│ │ │ │ │ PointcutAdvisor.java
│ │ │ │ │ TargetSource.java
│ │ │ │ │
│ │ │ │ ├─aspect
│ │ │ │ │ Aspect.java
│ │ │ │ │ AspectJExpressionPointcut.java
│ │ │ │ │ AspectJExpressionPointcutAdvisor.java
│ │ │ │ │ Before.java
│ │ │ │ │
│ │ │ │ ├─config
│ │ │ │ │ AopBeanRegistryPostProcessor.java
│ │ │ │ │
│ │ │ │ └─framework
│ │ │ │ │ AopProxy.java
│ │ │ │ │ Cglib2AopProxy.java
│ │ │ │ │ JdkDynamicAopProxy.java
│ │ │ │ │ ProxyFactory.java
│ │ │ │ │ ReflectiveMethodInvocation.java
│ │ │ │ │
│ │ │ │ ├─adapter
│ │ │ │ │ MethodBeforeAdviceInterceptor.java
│ │ │ │ │
│ │ │ │ └─autoproxy
│ │ │ │ DefaultAdvisorAutoProxyCreator.java
│ │ │ │
│ │ │ ├─beans
│ │ │ │ ├─exception
│ │ │ │ │ BeanException.java
│ │ │ │ │
│ │ │ │ └─factory
│ │ │ │ │ Aware.java
│ │ │ │ │ BeanClassLoaderAware.java
│ │ │ │ │ BeanFactory.java
│ │ │ │ │ BeanFactoryAware.java
│ │ │ │ │ BeanNameAware.java
│ │ │ │ │ ConfigurableListableBeanFactory.java
│ │ │ │ │ DisposableBean.java
│ │ │ │ │ FactoryBean.java
│ │ │ │ │ HierarchicalBeanFactory.java
│ │ │ │ │ InitializingBean.java
│ │ │ │ │ ListableBeanFactory.java
│ │ │ │ │ ObjectFactory.java
│ │ │ │ │ PropertyPlaceholderConfigurer.java
│ │ │ │ │
│ │ │ │ ├─annotation
│ │ │ │ │ Autowired.java
│ │ │ │ │ AutowiredAnnotationBeanPostProcessor.java
│ │ │ │ │ Qualifier.java
│ │ │ │ │ Value.java
│ │ │ │ │
│ │ │ │ ├─config
│ │ │ │ │ AutowireCapableBeanFactory.java
│ │ │ │ │ BeanDefinition.java
│ │ │ │ │ BeanDefinitionRegistryPostProcessor.java
│ │ │ │ │ BeanFactoryPostProcessor.java
│ │ │ │ │ BeanPostProcessor.java
│ │ │ │ │ BeanReference.java
│ │ │ │ │ ConfigurableBeanFactory.java
│ │ │ │ │ DefaultSingletonBeanRegistry.java
│ │ │ │ │ InstantiationAwareBeanPostProcessor.java
│ │ │ │ │ PropertyValue.java
│ │ │ │ │ PropertyValues.java
│ │ │ │ │ SingletonBeanRegistry.java
│ │ │ │ │
│ │ │ │ ├─support
│ │ │ │ │ AbstractAutowireCapableBeanFactory.java
│ │ │ │ │ AbstractBeanDefinitionReader.java
│ │ │ │ │ AbstractBeanFactory.java
│ │ │ │ │ BeanDefinitionReader.java
│ │ │ │ │ BeanDefinitionRegistry.java
│ │ │ │ │ CglibSubclassingInstantiationStrategy.java
│ │ │ │ │ DefaultListableBeanFactory.java
│ │ │ │ │ DisposableBeanAdapter.java
│ │ │ │ │ FactoryBeanRegistrySupport.java
│ │ │ │ │ InstantiationStrategy.java
│ │ │ │ │ SimpleInstantiationStrategy.java
│ │ │ │ │
│ │ │ │ └─xml
│ │ │ │ XmlBeanDefinitionReader.java
│ │ │ │
│ │ │ ├─context
│ │ │ │ │ ApplicationContext.java
│ │ │ │ │ ApplicationContextAware.java
│ │ │ │ │ ApplicationEvent.java
│ │ │ │ │ ApplicationEventPublisher.java
│ │ │ │ │ ApplicationListener.java
│ │ │ │ │ ConfigurableApplicationContext.java
│ │ │ │ │
│ │ │ │ ├─annotation
│ │ │ │ │ ClassPathBeanDefinitionScanner.java
│ │ │ │ │ ClassPathScanningCandidateComponentProvider.java
│ │ │ │ │ Scope.java
│ │ │ │ │
│ │ │ │ ├─event
│ │ │ │ │ AbstractApplicationEventMulticaster.java
│ │ │ │ │ ApplicationContextEvent.java
│ │ │ │ │ ApplicationEventMulticaster.java
│ │ │ │ │ ContextClosedEvent.java
│ │ │ │ │ ContextRefreshEvent.java
│ │ │ │ │ SimpleApplicationEventMulticaster.java
│ │ │ │ │
│ │ │ │ └─support
│ │ │ │ AbstractApplicationContext.java
│ │ │ │ AbstractRefreshableApplicationContext.java
│ │ │ │ AbstractXmlApplicationContext.java
│ │ │ │ ApplicationContextAwareProcessor.java
│ │ │ │ ClasspathXmlApplicationContext.java
│ │ │ │
│ │ │ ├─core
│ │ │ │ └─io
│ │ │ │ ClasspathResource.java
│ │ │ │ DefaultResourceLoader.java
│ │ │ │ FileSystemResource.java
│ │ │ │ Resource.java
│ │ │ │ ResourceLoader.java
│ │ │ │ UrlResource.java
│ │ │ │
│ │ │ ├─stereotype
│ │ │ │ Component.java
│ │ │ │
│ │ │ └─util
│ │ │ ClassUtils.java
│ │ │ StringValueResolver.java
│ │ │
│ │ └─resources
│ └─test
│ ├─java
│ │ └─com
│ │ └─akitsuki
│ │ └─springframework
│ │ └─test
│ │ │ ApiTest.java
│ │ │
│ │ └─bean
│ │ IUserService.java
│ │ UserDao.java
│ │ UserService.java
│ │ UserServiceBeforeAdvice.java
│ │
│ └─resources
│ application.yml
│ spring.xml
包装起来,提前暴露
这里我们有一个提前暴露的概念。什么是提前暴露呢?其实就是在Bean还没有完全创建好的时候,就可以让其他Bean来进行引用。那你可能会有一个疑问:我为什么要包装起来?我直接给它一个半成品Bean不好吗?你说的对,但是我们还要考虑一种情况:代理Bean。AOP是需要进行代理的,我们的原始Bean会被代理之后提供出去。这个时候如果我们的半成品Bean被引用了,那么引用的就是原始Bean,而不是代理之后的Bean,很显然,这里的代理功能也会失效。所以我们需要一个包装,来作为三级缓存的Bean。
package com.akitsuki.springframework.beans.factory;
import com.akitsuki.springframework.beans.exception.BeanException;
/**
* 用于在三级缓存时包装bean,解决循环依赖
* @author ziling.wang@hand-china.com
* @date 2022/12/15 16:18
*/
public interface ObjectFactory<T> {
T getObject() throws BeanException;
}
看到这个结构,很容易会联想到我们之前的FactoryBean。它们确实很类似,就连Spring官方的代码注释里面也提到了这一点。不过,这里的ObjectFactory只是用来包装Bean的,而FactoryBean,却是用来生产Bean的。
设置三级缓存
有了上面的包装,我们就可以着手进行三级缓存的设计了。这三级缓存是按照下面的规则进行的:
- 一级缓存:存放已经完全生产好、可以直接使用的单例bean
- 二级缓存:存放已经实例化好,但还没有进行属性填充的半成品单例bean
- 三级缓存:存放用ObjectFactory进行包装的bean(这时应该还不能叫bean)
其实一级缓存我们一直都有在用,就是我们的单例bean缓存。而现在我们要加上二级和三级缓存。这里我们要去动一下许久没有动过的类:DefaultSingletonBeanRegistry
。我们之前的单例bean缓存,现在被称为一级缓存,就在它里面。
package com.akitsuki.springframework.beans.factory.config;
import com.akitsuki.springframework.beans.exception.BeanException;
import com.akitsuki.springframework.beans.factory.DisposableBean;
import com.akitsuki.springframework.beans.factory.ObjectFactory;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* 默认的单例Bean注册获取实现
*
* @author ziling.wang@hand-china.com
* @date 2022/11/7 9:58
*/
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
protected static final Object NULL_OBJECT = new Object();
/**
* 一级缓存,存放已经处理完成的bean
*/
private final Map<String, Object> singletonBeans = new HashMap<>();
/**
* 二级缓存,存放半成品bean
*/
protected final Map<String, Object> earlySingletonObjects = new HashMap<>();
/**
* 三级缓存,存放代理对象
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();
private final Map<String, DisposableBean> disposableBeans = new HashMap<>();
@Override
public Object getSingleton(String beanName) {
//先从一级缓存中取
Object bean = singletonBeans.get(beanName);
if (null == bean) {
//从二级缓存中找
bean = earlySingletonObjects.get(beanName);
if (null == bean) {
//从三级缓存中找
ObjectFactory<?> factory = singletonFactories.get(beanName);
if (null != factory) {
bean = factory.getObject();
//将bean从三级缓存中移入二级缓存(移入的是getObject之后的结果),同时移除三级缓存中的数据
earlySingletonObjects.put(beanName, bean);
singletonFactories.remove(beanName);
}
}
}
return bean;
}
@Override
public void addSingleton(String beanName, Object singletonBean) {
//在添加单例bean的时候,放入一级缓存,同时要注意清理二级缓存和三级缓存
singletonBeans.put(beanName, singletonBean);
earlySingletonObjects.remove(beanName);
singletonFactories.remove(beanName);
}
/**
* 添加一个bean进入三级缓存
* 这里添加进入之后,要移除二级缓存中的数据
* 因为可能对于这个Bean,生成了多个三级缓存
* 而在前面的某个三级缓存已经被移入二级缓存
* 所以就需要移除掉二级缓存,以最新的三级缓存为主
* @param beanName
* @param objectFactory
*/
protected void addSingletonFactory(String beanName, ObjectFactory<?> objectFactory) {
if (!singletonFactories.containsKey(beanName)) {
singletonFactories.put(beanName, objectFactory);
earlySingletonObjects.remove(beanName);
}
}
@Override
public void registerDisposableBean(String beanName, DisposableBean bean) {
disposableBeans.put(beanName, bean);
}
/**
* 销毁单例对象
*/
public void destroySingletons() {
String[] keys = disposableBeans.keySet().toArray(new String[0]);
for (String key : keys) {
DisposableBean bean = disposableBeans.remove(key);
try {
bean.destroy();
} catch (Exception e) {
throw new BeanException("exception on destroy bean " + key, e);
}
}
}
}
我们来看一下变化。首先自然是类的属性里面,增加了二级缓存和三级缓存,都是 HashMap
。二级缓存和一级缓存类似,都是存储 Object
类型对象,也就是我们实际的Bean。三级缓存则存储 ObjectFactory
类型的对象,它不是真正的Bean,我们需要调用 getObject
方法,来获取需要的Bean。
接下来是 getSingleton
方法,这个是我们之前用来获取单例对象的方法,现在需要进行三级缓存的判断。过程其实就是一级一级缓存去找,找到了就返回。这里需要注意有些不同的是三级缓存的操作,三级缓存在取出bean之后,要将bean移入二级缓存,同时删除三级缓存的内容。为什么要这样操作呢?因为三级缓存实际存储的是一个Factory,工厂。这也就意味着,我们从三级缓存中每次 getObject
,实际上生产的都是一个新的对象,这不是我们想要的。既然是单例bean,那么就应该只有一份。
最后是 addSingleton
和 addSingletonFactory
方法,分别是添加单例bean和添加三级缓存的单例bean。在添加单例bean的时候,增加了移除二级和三级缓存的操作,很好理解,因为这个时候bean已经完全生产完成了,所以就不需要二级和三级缓存了。而添加三级缓存的时候,则需要移除二级缓存。
老大难:AOP
AOP一直是我们的老大难问题,因为它和一般的Bean不一样,它是需要进行代理增强的。一旦从代理这块走一圈之后,事情就会变得复杂起来。这也是为什么要设计三级缓存的原因。如果没有AOP这个代理的操作,其实只需要二级缓存就够了。就是因为有了代理,才需要第三级的缓存。
这里我们要根据三级缓存,对AOP的过程进行一些改造。首先是 InstantiationAwareBeanPostProcessor
的改造,这里要加一个方法:getEarlyBeanReference
。这个方法的作用是用来给前面的ObjectFactory生产bean的。对于一般的bean来说,这里直接返回bean本身就可以了。但是对于AOP的bean来说,则需要进行包装。
default Object getEarlyBeanReference(Object bean, String beanName) {
return bean;
}
可以看到,这个接口用了默认方法,如果子类不进行复写,则会默认返回bean本身。下面我们要做的,就是修改需要复写这个方法的子类:DefaultAdvisorAutoProxyCreator
。
package com.akitsuki.springframework.aop.framework.autoproxy;
import com.akitsuki.springframework.aop.*;
import com.akitsuki.springframework.aop.aspect.AspectJExpressionPointcutAdvisor;
import com.akitsuki.springframework.aop.framework.ProxyFactory;
import com.akitsuki.springframework.beans.exception.BeanException;
import com.akitsuki.springframework.beans.factory.BeanFactory;
import com.akitsuki.springframework.beans.factory.BeanFactoryAware;
import com.akitsuki.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.akitsuki.springframework.beans.factory.config.PropertyValues;
import com.akitsuki.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* @author ziling.wang@hand-china.com
* @date 2022/12/6 15:31
*/
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {
private DefaultListableBeanFactory beanFactory;
private final Set<Object> earlyProxyReference = Collections.synchronizedSet(new HashSet<>());
private boolean isInfrastructureClass(Class<?> beanClass) {
return Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeanException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeanException {
if (!earlyProxyReference.contains(beanName)) {
return wrapIfNecessary(bean);
}
return bean;
}
protected Object wrapIfNecessary(Object bean) {
if (isInfrastructureClass(bean.getClass())) {
return bean;
}
Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();
for (AspectJExpressionPointcutAdvisor advisor : advisors) {
ClassFilter classFilter = advisor.getPointcut().getClassFilter();
if (!classFilter.matches(bean.getClass())) {
continue;
}
AdvisedSupport advisedSupport = new AdvisedSupport();
TargetSource targetSource = new TargetSource(bean);
advisedSupport.setTargetSource(targetSource);
advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
advisedSupport.setProxyTargetClass(true);
return new ProxyFactory(advisedSupport).getProxy();
}
return bean;
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeanException {
return null;
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeanException {
return pvs;
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
earlyProxyReference.add(beanName);
return wrapIfNecessary(bean);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeanException {
this.beanFactory = (DefaultListableBeanFactory) beanFactory;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeanException {
return true;
}
}
我们来逐步分析。首先可以看到,增加了一个属性:earlyProxyReference
。它的作用我们下面再解释。然后可以看到,之前写在 postProcessAfterInitialization
中的逻辑,被移到了一个独立的方法:wrapIfNecessary
中。这里在调用之前,可以看到,会先判断 earlyProxyReference
中是否包含beanName。可以推断出,earlyProxyReference
是用来存储beanName的,它的作用就是防止bean被多次包装。在下面的 getEarlyBeanReference
方法中,我们可以看到,会在这里将beanName添加到 earlyProxyReference
中。
那么这里的 getEarlyBeanReference
方法会在什么时候被调用呢?我们下一节来介绍。
逃不了的生命周期
终究还是回到了生命周期这里。别的地方再怎么花里胡哨,终究还是要有一个启动点。那么这个启动点,就是创建bean的时候,我们几乎每次都要改的:AbstractAutowireCapableBeanFactory
。
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeanException {
Object bean;
try {
bean = resolveBeforeInstantiation(beanName, beanDefinition);
if (null != bean) {
return bean;
}
//实例化bean
bean = createBeanInstance(beanDefinition, beanName, args);
//处理循环依赖
if (beanDefinition.isSingleton()) {
Object finalBean = bean;
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, beanDefinition, finalBean));
}
boolean continueWithPropertyPopulation = applyBeanPostProcessorsAfterInstantiation(beanName, bean);
if (!continueWithPropertyPopulation) {
return bean;
}
//设置bean属性之前,允许beanPostProcessor修改属性值
applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);
//设置bean属性
applyPropertyValues(beanName, beanDefinition, bean);
//初始化bean,执行beanPostProcessor的前置和后置方法
bean = initializeBean(beanName, bean, beanDefinition);
} catch (Exception e) {
throw new BeanException("创建bean失败", e);
}
//注册实现了DisposableBean接口的对象
registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);
Object exposedObject = bean;
if (beanDefinition.isSingleton()) {
exposedObject = getSingleton(beanName);
//创建好的单例bean,放入缓存
addSingleton(beanName, exposedObject);
}
return exposedObject;
}
protected Object getEarlyBeanReference(String beanName, BeanDefinition beanDefinition, Object bean) {
Object exposedBean = bean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
if (processor instanceof InstantiationAwareBeanPostProcessor) {
exposedBean = ((InstantiationAwareBeanPostProcessor) processor).getEarlyBeanReference(exposedBean, beanName);
if (null == exposedBean) {
return null;
}
}
}
return exposedBean;
}
/**
* 对于返回false的bean,不再执行后续设置bean属性的操作
* @param beanName
* @param bean
* @return
*/
protected boolean applyBeanPostProcessorsAfterInstantiation(String beanName, Object bean) {
boolean continueWithPropertyPopulation = true;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
if (processor instanceof InstantiationAwareBeanPostProcessor) {
if (!((InstantiationAwareBeanPostProcessor) processor).postProcessAfterInstantiation(bean, beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
return continueWithPropertyPopulation;
}
我们首先看中间的方法 getEarlyBeanReference
,可以看到,这个方法和其他后置处理器的处理类似,都是遍历然后调用方法。这里可以看到前面提到的 getEarlyBeanReference
方法,就是在这里被调用的。那么问题又来了,这个方法在什么时候调用呢?那就得看看上面的 createBean
了。
我们看处理循环依赖那一段,在这里,我们将实例化好的初始bean,用 ObjectFactory
包装好,调用 addSingletonFactory
方法(还记得在哪里声明的这个方法吗?在单例bean注册类那里),添加到三级缓存中。这里有个点要注意,这里是采用lambda表达式+匿名内部类的方式进行的,可以认为这里的写法等效于新建了一个 ObjectFactory
的对象,而对象的 getObject
方法,内容就是调用 getEarlyBeanReference
方法。这样可以设想,当一个bean是普通bean的时候,调用 getEarlyBeanReference
,会走默认的直接返回原始bean。而一个bean被AOP代理之后,就会走到 DefaultAdvisorAutoProxyCreator
中,进行一系列包装,最终返回一个包装类。这样就解决了AOP的循环依赖问题。
最后的地方是针对之前的特殊创建bean方法的一个修改,一般这里都会返回true。当一个bean要走特殊创建流程的时候,这里就会返回false。然后在createBean中调用的时候,就会直接返回bean,不走下面的设置属性等流程。
最后还有一个地方需要注意一下,被cglib代理过的对象,是不能够被再次代理的。所以我们之前创建bean的时候,都是用cglib方式去创建,如果这里再去用cglib创建代理bean,就会报错。那么我们就需要将之前创建bean的方式修改为使用JDK普通方式进行创建,在 DefaultListableBeanFactory
中,将策略调整为 SimpleInstantiationStrategy
。
public DefaultListableBeanFactory() {
this(SimpleInstantiationStrategy.class);
}
public DefaultListableBeanFactory(Class<? extends InstantiationStrategy> clazz) {
super(clazz);
}
测试!
终于到了测试环节。这次的测试,其实代码方面基本不需要动,只需要把之前的测试类拷贝过来就可以了,我们需要IUserService接口、UserDao、UserService、UserServiceBeforeAdvice,还有主要测试类ApiTest。内容基本不用变动。
但是这里我们为了测试循环依赖,特地让UserDao再去依赖一下UserService。
package com.akitsuki.springframework.test.bean;
import com.akitsuki.springframework.beans.factory.DisposableBean;
import com.akitsuki.springframework.beans.factory.InitializingBean;
import com.akitsuki.springframework.beans.factory.annotation.Autowired;
import com.akitsuki.springframework.context.annotation.Scope;
import com.akitsuki.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author ziling.wang@hand-china.com
* @date 2022/11/8 14:42
*/
@Component
public class UserDao implements InitializingBean, DisposableBean {
private static final Map<Long, String> userMap = new HashMap<>();
@Autowired
private IUserService userService;
public String queryUserName(Long id) {
return userMap.get(id);
}
@Override
public void destroy() throws Exception {
System.out.println("执行UserDao的destroyMethod");
userMap.clear();
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("执行UserDao的initMethod");
userMap.put(1L, "akitsuki");
userMap.put(2L, "toyosaki");
userMap.put(3L, "kugimiya");
userMap.put(4L, "hanazawa");
userMap.put(5L, "momonogi");
}
}
测试结果:
userService的afterPropertiesSet执行了
执行UserDao的initMethod
方法执行了:public void com.akitsuki.springframework.test.bean.UserService.queryUserInfo(java.lang.Long)
dummyString:kamisama
dummyInt:114514
用户名:akitsuki
执行UserDao的destroyMethod
userService的destroy执行了
Process finished with exit code 0
可以看到,正常工作,各种初始化方法和销毁方法都正常工作,切面也正常工作,证明我们的循环依赖成功进行了。
那么在最后,我们再来梳理一下Spring解决循环依赖的步骤。就用这里的UserService和UserDao来举例子,假设Spring先构建UserDao。
- 创建UserDao,这时放入三级缓存;
- 解决UserDao的属性注入,在这一步,UserDao已经从三级缓存放入了二级缓存,发现UserDao依赖UserService;
- 创建UserService,放入三级缓存;
- 解决UserService的属性注入,在这一步从三级缓存取出对象的时候,完成了UserService的AOP代理包装步骤。放入二级缓存,发现UserService依赖UserDao;
- 从二级缓存中找到UserDao,让UserService成功依赖,UserService创建完成,放入一级缓存;
- 回到UserDao的属性注入解决过程,这时候拿到了创建好的UserService,成功依赖,UserDao创建完成,放入一级缓存
以上就是解决循环依赖的全部过程。说实话,我在调试这段程序的时候,花了很长时间,因为一个地方写的有些问题,来回调试,AOP总是无法成功代理,使用的总是原始对象。最后经过多次的断点调试,终于是找到了问题所在。好在经过这些断点调试,也让我搞明白了循环依赖的解决过程。所以如果觉得这里还是有些不清楚,不妨把程序跑起来,断点跟踪一遍,说不定会帮助理解。
相关源码可以参考我的gitee:https://gitee.com/akitsuki-kouzou/mini-spring
,这里对应的代码是mini-spring-16