本文主要分析Spring的循环依赖问题。开始正文之前,我们需要定义这2个类。LoopReferenceA中引用LoopReferenceB,LoopReferenceB中引用LoopReferenceA。
/**
* @author cmazxiaoma
* @version V1.0
* @Description: TODO
* @date 2018/8/14 15:42
*/@Componentpublic class LoopReferenceA { @Autowired
private LoopReferenceB loopReferenceB;// public LoopReferenceA(@Autowired LoopReferenceB loopReferenceB) {// this.loopReferenceB = loopReferenceB;// }}/**
* @author cmazxiaoma
* @version V1.0
* @Description: TODO
* @date 2018/8/14 15:43
*/@Componentpublic class LoopReferenceB { @Autowired
private LoopReferenceA loopReferenceA;
}分析
AbstractApplicationContext中的refresh()方法是Spring中很核心的方法。Spring中所有的方法初始化都是在这个方法中完成的,用于容器初始化。refresh()里面的细节我就不多说了,本文篇幅有限。只是大致过一下概念,有利于我们后面追踪分析问题。
prepareRefresh():容器预先准备,记录容器启动时间和进行标记状态
obtainFreshBeanFactory():创建BeanFactory。如果已经存在该工厂,那么销毁其里面的beans和自行关闭。如果没有,则创建工厂,并且进行装载BeanDefinition
prepareBeanFactory(): 配置BeanFactory的上下文,比如classLoader和BeanPostProcessor,注册一些需要解决的依赖和需要忽略的依赖、注册涉及容器系统环境的bean等等。
postProcessBeanFactory():模板方法,在BeanDefinition被装载后(所有BeanDefinition被加载,但是没有bean被实例化),提供一个修改beanFactory容器的入口。
invokeBeanFactoryPostProcessor():在Bean未开始实例之前,提供BeanDefinition修改或者注册的入口。我们熟悉的PropertyPlaceHolderConfigurer就是在这里调用的。
registerBeanPostProcessor():用于拦截Bean创建的BeanPostProcessor。
initMessageSource():初始化容器所需要的MessageSource,用于国际化处理
initApplicationEventMulticaster():初始化容器的事件广播器。
onRefresh():模板方法
registerListeners():注册监听器
finishBeanFactoryInitialization():完成容器的初始化,里面会调用preInstantiateSingletons()完成单例对象的创建。
@Override
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 1.Prepare this context for refreshing.
prepareRefresh(); // 2.Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 3.Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory); try { // 4.Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory); // 5.Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory); // 6.Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory); // 7.Initialize message source for this context.
initMessageSource(); // 8.Initialize event multicaster for this context.
initApplicationEventMulticaster(); // 9.Initialize other special beans in specific context subclasses.
onRefresh(); //10. Check for listener beans and register them.
registerListeners(); // 11.Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory); //12. Last step: publish corresponding event.
finishRefresh();
} catch (BeansException ex) { if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex);
} // Destroy already created singletons to avoid dangling resources.
destroyBeans(); // Reset 'active' flag.
cancelRefresh(ex); // Propagate exception to caller.
throw ex;
} finally { // Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}我们只用关注beanFactory.preInstantiateSingletons()方法。这个方法用于创建单例且是急加载的对象。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
} // Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(new StringValueResolver() { @Override
public String resolveStringValue(String strVal) { return getEnvironment().resolvePlaceholders(strVal);
}
});
} // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
} // Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null); // Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration(); // Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();这个方法是位于DefaultListableBeanFactory中,这个类实现BeanDefinitionRegistry接口,通过重写的registerBeanDefinition注册容器中的BeanDefinition。遍历所有的BeanDefinitionNames,从mergedBeanDefinitions中获取RootBeanDefinition。如果bean不是抽象且是单例且是急加载的话,那么进行下一步判断。如果bean是FactoryBean类型,还需要判断里面的object是否急加载。如果是的话,直接调用getBean(beanName)完成创建。如果bean不是FactoryBean类型的话,直接调用getBean(beanName)。
@Override
public void preInstantiateSingletons() throws BeansException { if (this.logger.isDebugEnabled()) { this.logger.debug("Pre-instantiating singletons in " + this);
} // Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { @Override
public Boolean run() { return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
} else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
} if (isEagerInit) {
getBean(beanName);
}
} else {
getBean(beanName);
}
}
} // Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override
public Object run() {
smartSingleton.afterSingletonsInstantiated(); return null;
}
}, getAccessControlContext());
} else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}AbstractBeanFactory中的getBean(name),看来是实现了BeanFactory接口的getBean(name)方法,里面调用的是AbstractAutowireCapableBeanFactory中的doGetBean()方法。
//---------------------------------------------------------------------
// Implementation of BeanFactory interface
//---------------------------------------------------------------------
@Override
public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false);
}别被这么长的代码吓到了,其实核心的代码也就那么多。分析源码的时候,不要被边边角角的代码带偏,我们只用抓住核心代码,卷起衣袖开干即可。何况网上有很多大神写的关于框架源码分析的博客,站在巨人上面的我们事半功倍。
protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException { final String beanName = transformedBeanName(name);
Object bean; // Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isDebugEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
} else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else { // Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName);
} // Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent.
String nameToLookup = originalBeanName(name); if (args != null) { // Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
} else { // No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
} if (!typeCheckOnly) {
markBeanAsCreated(beanName);
} try { final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
getBean(dep);
}
} // Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override
public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args);
} catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName); throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) { // It's a prototype -> create a new instance.
Object prototypeInstance = null; try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
} finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
} try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() { @Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args);
} finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
} catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
} catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName); throw ex;
}
} // Check if required type matches the type of the actual bean instance.
if (requiredType != null && bean != null && !requiredType.isInstance(bean)) { try { return getTypeConverter().convertIfNecessary(bean, requiredType);
} catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
} throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
} return (T) bean;
}抓住Object sharedInstance = getSingleton(beanName);这行代码,我们追踪这行代码,会发现最终调用的是DefaultSingletonBeanRegistry中的getSingleton()方法。这里指的注意是allowEarlyReference的值是true,说明允许提前暴露bean的引用。getSingleton()的作用是检查缓存中或者是实例工厂中是否有对应的bean,这主要是解决了Spring循环依赖的问题。因为在创建单例LoopReferenceA对象的时候,会存在依赖LoopReferenceB对象。而创建LoopReferenceB的时候避免出现循环依赖的问题,Spring会在LoopReferenceA对象还没有创建完成之前将创建LoopReferenceA对象的ObjectFactory暴露出来,并且加入到singletonFactories缓存中。当LoopReferenceB对象创建的时候,直接从singletonFactories缓存中拿到LoopReferenceA的ObjectFactory,再从ObjectFactory获取LoopReferenceA的实例即可。其实这个时候已经真相大白了,但是我们还需要继续追踪,好对Spring这个流程有个更加清晰的概念。
@Override
public Object getSingleton(String beanName) { return getSingleton(beanName, true);
} 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 != NULL_OBJECT ? singletonObject : null);
}如果名字为name的bean实例只是普通的实例,那么直接返回beanInstance。如果是FactoryBean类型的,获取其的object对象,将其返回即可。
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { // Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
} // Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance;
} Object object = null; if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
} if (object == null) { // Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance; // Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
} return object;
}如果获取sharedInstance(提前暴露的对象)为null的话,会执行到这里。Spring只会处理单例情况下出现的循环依赖的问题。而对于采取ProtoType策略创建的bean,则不会去解决。如果LoopRefereceA和LoopReferenceB都指定@Scope("prototype"),那这里肯定会抛出如图所示的错误。
作者:cmazxiaoma
链接:https://www.jianshu.com/p/768525bf9f30