spring处理循环依赖时序图_面试官:Spring是怎么解决循环依赖的呢?小伙子你来说说看?

前言

Spring大家族功能强大,模块复杂繁多。就Spring Framework模块而言,核心功能只有两个:IoC和AOP。本篇主要从源码的角度讲解Spring容器中一些重要的接口、Spring如何解决循环依赖等

本篇使用的Spring版本为5.2.2.RELEASE。

Spring的源码错综复杂,并且类名一般都比较长,并且调用层次较深。因此阅读起来有一定的难度,所以阅读的时候可以先从大体上理解整个流程,而不需要逐行的阅读。不然很容易陷入细节而无法自拔,导致事倍功半。

在深入Spring源码之前,需要先了解几个非常重要的接口,理解他们,是理解Spring容器启动的关键。

核心接口

BeanDefinition

BeanDefinition是Spring中非常重要的一个接口,定义于spring-beans模块中,其定义如下:

/** * A BeanDefinition describes a bean instance, which has property values, * constructor argument values, and further information supplied by * concrete implementations. * * 

This is just a minimal interface: The main intention is to allow a * {@link BeanFactoryPostProcessor} to introspect and modify property values * and other bean metadata. * */public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {}

根据接口描述,我们可以知道

BeanDefinition描述了一个bean实例,它具有属性值,构造函数参数值以及具体实现提供的更多信息。

看完类的描述,我们似乎依然不知道这个接口是用来干嘛的。

就博主自己的理解,BeanDefinition主要做用是定义了一个Spring Bean的元信息(metadata)的抽象。使得不管是XML文件配置的Spring Bean、注解扫描的Spring Bean,还是Java Config类配置Spring Bean,都能一个统一的抽象来表示,这个抽象就是BeanDefinition。

接下来看一下这个接口里面的(部分)内容,可以帮助理解这个接口的作用

/** 返回当前bean实例是否是单例 */boolean isSingleton();/** 返回当前bean是否应该被懒加载 */boolean isLazyInit();/** 返回bean的类名称 */@NullableString getBeanClassName();123456789

从这个几个接口方法的描述就可以看出BeanDefinition可以描述Spring Bean的元信息

在我们学习Java的时候其实已经接触过这样的类,那就是java.lang.Class类,Class就是用来描述JDK中各个类的元信息的抽象,我们可以从Class类获取类的名称、构造函数、字段等信息。

BeanFactory

BeanFactory是Spring中非常重要的一个接口,定义于spring-beans模块中,其定义如下:

/** * The root interface for accessing a Spring bean container. * This is the basic client view of a bean container; * further interfaces such as {@link ListableBeanFactory} and * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory} * are available for specific purposes. * * 

Bean factory implementations should support the standard bean lifecycle interfaces * as far as possible. The full set of initialization methods and their standard order is: *

* BeanNameAware's {@code setBeanName} * BeanClassLoaderAware's {@code setBeanClassLoader} * BeanFactoryAware's {@code setBeanFactory} * EnvironmentAware's {@code setEnvironment} * EmbeddedValueResolverAware's {@code setEmbeddedValueResolver} * ResourceLoaderAware's {@code setResourceLoader} (only applicable when running in an application context) * ApplicationEventPublisherAware's {@code setApplicationEventPublisher} (only applicable when running in an application context) * MessageSourceAware's {@code setMessageSource} (only applicable when running in an application context) * ApplicationContextAware's {@code setApplicationContext} (only applicable when running in an application context) * ServletContextAware's {@code setServletContext} (only applicable when running in a web application context) * {@code postProcessBeforeInitialization} methods of BeanPostProcessors * InitializingBean's {@code afterPropertiesSet} * a custom init-method definition * {@code postProcessAfterInitialization} methods of BeanPostProcessors * * *

On shutdown of a bean factory, the following lifecycle methods apply: *

* {@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors * DisposableBean's {@code destroy} * a custom destroy-method definition * * */public interface BeanFactory {}

从接口注释和接口定义就可以知道,BeanFactory是Spring容器的顶级接口。并且注释中也给出了全套初始化方法及其标准顺序。

由于是顶层接口,所以定义的方法比较少,最核心的方法当属getBean

/** 从Spring容器中获取bean实例 */ T getBean(Class requiredType) throws BeansException;/** 从Spring容器中获取bean实例 */Object getBean(String name) throws BeansException;

ApplicationContext

BeanFactory是Spring的顶级接口,从BeanFactory中已经能够获取Spring Bean实例了,但是Spring依然提供了一个用来扩展BeanFactory的接口,那就是ApplicationContext,该接口是BeanFactory的超集。定义在spring-context模块中。

/** * Central interface to provide configuration for an application. * This is read-only while the application is running, but may be * reloaded if the implementation supports this. * * 

An ApplicationContext provides: *

* Bean factory methods for accessing application components. * Inherited from {@link org.springframework.beans.factory.ListableBeanFactory}. * The ability to load file resources in a generic fashion. * Inherited from the {@link org.springframework.core.io.ResourceLoader} interface. * The ability to publish events to registered listeners. * Inherited from the {@link ApplicationEventPublisher} interface. * The ability to resolve messages, supporting internationalization. * Inherited from the {@link MessageSource} interface. * Inheritance from a parent context. Definitions in a descendant context * will always take priority. This means, for example, that a single parent * context can be used by an entire web application, while each servlet has * its own child context that is independent of that of any other servlet. * * *

In addition to standard {@link org.springframework.beans.factory.BeanFactory} * lifecycle capabilities, ApplicationContext implementations detect and invoke * {@link ApplicationContextAware} beans as well as {@link ResourceLoaderAware}, * {@link ApplicationEventPublisherAware} and {@link MessageSourceAware} beans. * */public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,MessageSource, ApplicationEventPublisher, ResourcePatternResolver {}

根据类的描述可以知道这是一个中央接口,为应用程序提供配置。这个接口主要用来扩展BeanFactory的功能。ApplicationContext接口提供了如下功能

  • 用于访问应用程序组件的Bean工厂方法
  • 以通用方式加载文件资源的能力
  • 将事件发布给注册的侦听器的能力
  • 处理消息的能力,支持国际化

BeanPostProcessor

BeanPostProcessor是Spring中非常重要的一个接口,定义于spring-beans模块中,其定义如下:

/** * Factory hook that allows for custom modification of new bean instances — * for example, checking for marker interfaces or wrapping beans with proxies. * * 

Typically, post-processors that populate beans via marker interfaces * or the like will implement {@link #postProcessBeforeInitialization}, * while post-processors that wrap beans with proxies will normally * implement {@link #postProcessAfterInitialization}. * *

Registration

*

An {@code ApplicationContext} can autodetect {@code BeanPostProcessor} beans * in its bean definitions and apply those post-processors to any beans subsequently * created. A plain {@code BeanFactory} allows for programmatic registration of * post-processors, applying them to all beans created through the bean factory. * *

Ordering

*

{@code BeanPostProcessor} beans that are autodetected in an * {@code ApplicationContext} will be ordered according to * {@link org.springframework.core.PriorityOrdered} and * {@link org.springframework.core.Ordered} semantics. In contrast, * {@code BeanPostProcessor} beans that are registered programmatically with a * {@code BeanFactory} will be applied in the order of registration; any ordering * semantics expressed through implementing the * {@code PriorityOrdered} or {@code Ordered} interface will be ignored for * programmatically registered post-processors. Furthermore, the * {@link org.springframework.core.annotation.Order @Order} annotation is not * taken into account for {@code BeanPostProcessor} beans. * */public interface BeanPostProcessor {}

在Spring的源码中可以看到很多PostProcessor相关的接口和类,比如BeanPostProcessor、BeanFactoryPostProcessor。*PostProcessor是后置处理器,用来对已经被创建,但是尚未初始化完成的对象进行一些增强操作

启动Spring

想要启动一个Spring容器很简单,只需要几行代码。

public class SpringBeanLifecycle {    public static void main(String[] args) {        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");        applicationContext.getBean(Student.class);    }}

其中applicationContext.xml是Spring的配置文件

<?xml version="1.0" encoding="UTF-8"?>

而Student类仅仅是为了注入Spring容器,无实际内容。

其实仅仅一行代码,就已经启动了Spring,那就是new ClassPathXmlApplicationContext("applicationContext.xml")。所以我们需要深入连接这个构造方法执行了哪些内容

/** * Create a new ClassPathXmlApplicationContext, loading the definitions * from the given XML file and automatically refreshing the context. * @param configLocation resource location * @throws BeansException if context creation failed */public ClassPathXmlApplicationContext(String configLocation) throws BeansException {this(new String[] {configLocation}, true, null);}
/** * Create a new ClassPathXmlApplicationContext with the given parent, * loading the definitions from the given XML files. * @param configLocations array of resource locations * @param refresh whether to automatically refresh the context, * loading all bean definitions and creating all singletons. * Alternatively, call refresh manually after further configuring the context. * @param parent the parent context * @throws BeansException if context creation failed * @see #refresh() */public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)throws BeansException {super(parent);// configLocations是加载的配置文件的名称数字,因此该方法主要的作用就是设置配置文件setConfigLocations(configLocations);if (refresh) {// 该方法就是启动Spring容器的核心方法refresh();}}

refresh

refresh方法执行的逻辑就是Spring容器启动的完整过程,其定义如下

@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.// 完成包(类)的扫描invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.// 注册后置处理器registerBeanPostProcessors(beanFactory);// Initialize message source for this context.// 国际化initMessageSource();// Initialize event multicaster for this context.初始化事件多播initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.// 初始化所有的非懒加载的单例bean,核心方法finishBeanFactoryInitialization(beanFactory);// 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();}}}

该方法虽然调用了很多其他方法,但是真正创建Spring Bean的逻辑是finishBeanFactoryInitialization方法。

finishBeanFactoryInitialization

/** * Finish the initialization of this context's bean factory, * initializing all remaining singleton beans. */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(strVal -> 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.// 初始化所有的非懒加载的单例bean,核心方法beanFactory.preInstantiateSingletons();}

preInstantiateSingletons

@Overridepublic void preInstantiateSingletons() throws BeansException {if (logger.isTraceEnabled()) {logger.trace("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 beanNames = new ArrayList<>(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...// 触发所有非懒加载的单例beanfor (String beanName : beanNames) {// RootBeanDefinition是BeanDefinition的子类// 也就是spring bean的元信息的抽象,用来判断该bean是不是应该被初始化RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {// 如果是非抽象、非懒加载的单例bean,就应该被初始化if (isFactoryBean(beanName)) {Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {final FactoryBean> factory = (FactoryBean>) bean;boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged((PrivilegedAction)((SmartFactoryBean>) factory)::isEagerInit,getAccessControlContext());}else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean>) factory).isEagerInit());}if (isEagerInit) {getBean(beanName);}}}else {// 该方法才是真正的实例化spring beangetBean(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((PrivilegedAction) () -> {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else {smartSingleton.afterSingletonsInstantiated();}}}}
d3cba5225312780f25f2d4b3ffc9e22e.png

从调试信息可以看到,bd是RootBeanDefinition,也就是BeanDefinition,它定义了Bean的元信息。

getBean

@Overridepublic Object getBean(String name) throws BeansException {return doGetBean(name, null, null, false);}

doGetBean

该方法用于创建或者查询bean

/** * Return an instance, which may be shared or independent, of the specified bean. */@SuppressWarnings("unchecked")protected  T doGetBean(final String name, @Nullable final Class requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {// 校验bean的名称final String beanName = transformedBeanName(name);Object bean;// Eagerly check singleton cache for manually registered singletons.// 从单例池中获取对象,该方法非常重要,后文详解// 由于容器在这里第一次尝试创建或者获取bean,所以返回值为nullObject sharedInstance = getSingleton(beanName);if (sharedInstance != null && args == null) {if (logger.isTraceEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +"' that is not fully initialized yet - a consequence of a circular reference");}else {logger.trace("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 (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}else if (args != null) {// Delegation to parent with explicit args.return (T) parentBeanFactory.getBean(nameToLookup, args);}else if (requiredType != null) {// No args -> delegate to standard getBean method.return parentBeanFactory.getBean(nameToLookup, requiredType);}else {return (T) parentBeanFactory.getBean(nameToLookup);}}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);try {getBean(dep);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}}// Create bean instance.if (mbd.isSingleton()) {// student对象是单例,所以执行该逻辑,此处再次调用getSingleton方法// 不过与上面不同的是,此处调用的是重载的方法sharedInstance = getSingleton(beanName, () -> {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, () -> {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 && !requiredType.isInstance(bean)) {try {T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);if (convertedBean == null) {throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}return convertedBean;}catch (TypeMismatchException ex) {if (logger.isTraceEnabled()) {logger.trace("Failed to convert bean '" + name + "' to required type '" +ClassUtils.getQualifiedName(requiredType) + "'", ex);}throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}}return (T) bean;}

该方法中调用了三个非常重要的方法,分别是两个重载的getSingleton方法和createBean方法。

getSingleton

该方法定义如下

@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) {// 从单例缓存池中获取单例对象Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {// 获取的对象为null,且该单例对象正在被创建// 但是它的调用时间是在getSingleton方法(也就是当前方法)之后// 所以此处的isSingletonCurrentlyInCreation方法返回的是false// 两个条件只满足了第一个,所以不会进入下面的逻辑// 后面的逻辑会调用一个方法标识单例bean正在被创建,之后再调用isSingletonCurrentlyInCreation()方法会返回truesynchronized (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);}}}}// 直接返回nullreturn singletonObject;}

从方法的实现可以看到,Spring取单例对象是从singletonObjects对象中取的,该对象定义如下

/** Cache of singleton objects: bean name to bean instance. */private final Map singletonObjects = new ConcurrentHashMap<>(256);

实际上singletonObjects就是Spring Bean的单例对象缓存池,里面存放的就是所有已经被Spring创建的单例bean实例(经历了完整的Spring Bean初始化生命周期)。有的地方也叫做Spring的一级缓存,本质上就是一个Map。

除此之外,还在earlySingletonObjects中根据beanName查找,如果没有就加入。earlySingletonObjects对象定义如下

/** Cache of early singleton objects: bean name to bean instance. */private final Map earlySingletonObjects = new HashMap<>(16);

可以看到,earlySingletonObjects也是一个缓存,存放的是尚未初始完成(已经被创建,但是尚未完成Spring初始化生命周期,也就是半成品)bean。有的地方也叫做二级缓存,本质也是个Map。

除此之外,还有一个缓存叫singletonFactories,其定义如下

/** Cache of singleton factories: bean name to ObjectFactory. */private final Map> singletonFactories = new HashMap<>(16);

该对象也是一个缓存,用于缓存尚未完成初始化对象的Bean工厂,也叫做三级缓存,本质也是个Map。至此,关于Spring解决循环依赖的三个缓存都已经出现了

/** * 一级缓存,用于存放已经初始化完成的Spring Bean(经历了完整的Spring Bean初始化生命周期 ) */private final Map singletonObjects = new ConcurrentHashMap<>(256);/** * 二级缓存,用于存放已经被创建,但是尚未初始化完成的Bean(尚未经历了完整的Spring Bean初始化生命周期 ) * 这种对象提前暴露出来,就是为了解决循环引用,避免“鸡生蛋,蛋生鸡”的问题 */private final Map earlySingletonObjects = new HashMap<>(16);/** * 三级缓存,用于存放二级缓存中Bean的工厂 */private final Map> singletonFactories = new HashMap<>(16);

这个方法在整个Spring Bean初始化的过程中被调用了很多次,应该算是最重要的方法之一了。想要读懂Spring解决循环依赖,务必反复阅读此方法。

第二个getSingleton方法定义如下

public Object getSingleton(String beanName, ObjectFactory> singletonFactory) {Assert.notNull(beanName, "Bean name must not be null");synchronized (this.singletonObjects) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {if (this.singletonsCurrentlyInDestruction) {throw new BeanCreationNotAllowedException(beanName,"Singleton bean creation not allowed while singletons of this factory are in destruction " +"(Do not request a bean from a BeanFactory in a destroy method implementation!)");}if (logger.isDebugEnabled()) {logger.debug("Creating shared instance of singleton bean '" + beanName + "'");}// 该方法标记单例bean正在被创建beforeSingletonCreation(beanName);boolean newSingleton = false;boolean recordSuppressedExceptions = (this.suppressedExceptions == null);if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();}try {singletonObject = singletonFactory.getObject();newSingleton = true;}catch (IllegalStateException ex) {// Has the singleton object implicitly appeared in the meantime ->// if yes, proceed with it since the exception indicates that state.singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {throw ex;}}catch (BeanCreationException ex) {if (recordSuppressedExceptions) {for (Exception suppressedException : this.suppressedExceptions) {ex.addRelatedCause(suppressedException);}}throw ex;}finally {if (recordSuppressedExceptions) {this.suppressedExceptions = null;}afterSingletonCreation(beanName);}if (newSingleton) {addSingleton(beanName, singletonObject);}}return singletonObject;}}

这个方法里调用了beforeSingletonCreation方法,作用是标记此单例bean正在被创建是Spring解决循环依赖的关键操作之一

createBean

createBean方法是Spring真正创建Bean的方法,也是Spring Bean的生命周期的开始。方法定义如下

@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {if (logger.isTraceEnabled()) {logger.trace("Creating instance of bean '" + beanName + "'");}RootBeanDefinition mbdToUse = mbd;// Make sure bean class is actually resolved at this point, and// clone the bean definition in case of a dynamically resolved Class// which cannot be stored in the shared merged bean definition.Class> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// Prepare method overrides.try {mbdToUse.prepareMethodOverrides();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),beanName, "Validation of method overrides failed", ex);}try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {return bean;}}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,"BeanPostProcessor before instantiation of bean failed", ex);}try {// 真正创建Spring BeanObject beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {// A previously detected exception with proper bean creation context already,// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.throw ex;}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);}}

doCreateBean

该方法用于创建Spring Bean,经过层层套娃,终于来到了重点,该方法定义如下

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {// 调用构造方法创建对象instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}final Object bean = instanceWrapper.getWrappedInstance();Class> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// Allow post-processors to modify the merged bean definition.synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.// 此处是Spring解决循环引用的关键// 第一个条件判断当前bean是否是单例,也就说明Spring只支持单例Bean的循环引用// 第二个条件默认是true,也就说Spring默认是支持循环引用的,如果想要关闭循环引用,把这个值设置成false即可// 第三个条件就是判断当前bean是否正在被创建,由于之前已经调用过beforeSingletonCreation方法,所以这个条件为trueboolean 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");}// 如果支持循环引用,就加入到一个集合,也就是【提前暴露出来】addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.// 初始化bean实例Object exposedObject = bean;try {// 填充属性,也就是自动注入populateBean(beanName, mbd, instanceWrapper);// 真正的初始Spring BeanexposedObject = initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been " +"wrapped. This means that said other beans do not use the final version of the " +"bean. This is often the result of over-eager type matching - consider using " +"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");}}}}// Register bean as disposable.try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject;}

在这个方法中,最重要的调用方法有三个createBeanInstance、populateBean和initializeBean。

  • createBeanInstance:调用构造方法创建对象
  • populateBean:填充属性
  • initializeBean:初始化给定的bean实例,应用工厂回调以及init方法和bean后置处理器

解决循环依赖的关键就是在第一步和第二步之间,判断当前bean是否需要支持循环引用,如果需要,就提前暴露出去,这时候暴露出去的bean是尚未完成初始化的bean,也就是所谓的半成品

理解了这三个步骤,再结合getSingleton方法的逻辑,相信Spring解决循环依赖的思路已经非常明确了。

总结

Spring源码庞大且繁杂,想要在短时间内读懂不太可能,不如先带着问题去读某个部分。

作者:Sicimike

原文链接:https://blog.csdn.net/Baisitao_/article/details/107349302

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值