程序员的成长之路

互联网/程序员/技术/资料共享

关注

阅读本文大概需要 17 分钟。

来自:blog.csdn.net/Baisitao_/article/details/107349302

前言

Spring大家族功能强大,模块复杂繁多。就Spring Framework模块而言,核心功能只有两个:IoCAOP

本篇主要从源码的角度讲解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.** <p>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的类名称 */
@Nullable
String getBeanClassName();

从这个几个接口方法的描述就可以看出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.** <p>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:* <ol>* <li>BeanNameAware's {@code setBeanName}* <li>BeanClassLoaderAware's {@code setBeanClassLoader}* <li>BeanFactoryAware's {@code setBeanFactory}* <li>EnvironmentAware's {@code setEnvironment}* <li>EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}* <li>ResourceLoaderAware's {@code setResourceLoader} (only applicable when running in an application context)* <li>ApplicationEventPublisherAware's {@code setApplicationEventPublisher} (only applicable when running in an application context)* <li>MessageSourceAware's {@code setMessageSource} (only applicable when running in an application context)* <li>ApplicationContextAware's {@code setApplicationContext} (only applicable when running in an application context)* <li>ServletContextAware's {@code setServletContext} (only applicable when running in a web application context)* <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors* <li>InitializingBean's {@code afterPropertiesSet}* <li>a custom init-method definition* <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors* </ol>** <p>On shutdown of a bean factory, the following lifecycle methods apply:* <ol>* <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors* <li>DisposableBean's {@code destroy}* <li>a custom destroy-method definition* </ol>**/
public interface BeanFactory {
}

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

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

/** 从Spring容器中获取bean实例 */
<T> T getBean(Class<T> 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.** <p>An ApplicationContext provides:* <ul>* <li>Bean factory methods for accessing application components.* Inherited from {@link org.springframework.beans.factory.ListableBeanFactory}.* <li>The ability to load file resources in a generic fashion.* Inherited from the {@link org.springframework.core.io.ResourceLoader} interface.* <li>The ability to publish events to registered listeners.* Inherited from the {@link ApplicationEventPublisher} interface.* <li>The ability to resolve messages, supporting internationalization.* Inherited from the {@link MessageSource} interface.* <li>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.* </ul>** <p>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 &mdash;* for example, checking for marker interfaces or wrapping beans with proxies.** <p>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}.** <h3>Registration</h3>* <p>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.** <h3>Ordering</h3>* <p>{@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相关的接口和类,比如BeanPostProcessorBeanFactoryPostProcessor*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"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="student" class="com.sicimike.bean.lifecycle.Student"></bean>
</beans>

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容器启动的完整过程,其定义如下

@Override
public 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

@Override
public 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<String> 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<Boolean>)((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<Object>) () -> {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else {smartSingleton.afterSingletonsInstantiated();}}}
}

preInstantiateSingletons@row.1

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

getBean

@Override
public 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> T doGetBean(final String name, @Nullable final Class<T> 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

该方法定义如下

@Nullable
protected 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<String, Object> 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<String, Object> earlySingletonObjects = new HashMap<>(16);

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

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

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

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

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

@Override
protected 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<String> 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;
}

在这个方法中,最重要的调用方法有三个createBeanInstancepopulateBeaninitializeBean

  • createBeanInstance:调用构造方法创建对象

  • populateBean:填充属性

  • initializeBean:初始化给定的bean实例,应用工厂回调以及init方法和bean后置处理器

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

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

总结

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

<END>

推荐阅读:

【170期】面试官:你能分别谈谈innodb下的记录锁,间隙锁,next-key锁吗?

【169期】面试官:同学,分析一下MySQL/InnoDB的加锁过程吧

【168期】面试官:框架中处处可见反射的运用,你对它了解多少?

5T技术资源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,单片机,树莓派,等等。在公众号内回复「2048」,即可免费获取!!

微信扫描二维码,关注我的公众号

朕已阅 

【171期】面试官:小伙汁,Spring是怎么解决循环依赖的呢?相关推荐

  1. 互相引用 spring_听说你还不知道Spring是如何解决循环依赖问题的?

    作者:Vt 前言 Spring如何解决的循环依赖,是近两年流行起来的一道Java面试题. 其实笔者本人对这类框架源码题还是持一定的怀疑态度的. 如果笔者作为面试官,可能会问一些诸如"如果注入 ...

  2. Spring是如何解决循环依赖的

    在关于Spring的面试中,我们经常会被问到一个问题,就是Spring是如何解决循环依赖的问题的.这个问题算是关于Spring的一个高频面试题,因为如果不刻意研读,相信即使读过源码,面试者也不一定能够 ...

  3. 万字长文带你吃透Spring是怎样解决循环依赖的

    在Spring框架中,处理循环依赖一直是一个备受关注的话题.这是因为Spring源代码中为了解决循环依赖问题,进行了大量的处理和优化.同时,循环依赖也是Spring高级面试中的必考问题,回答得好可以成 ...

  4. Spring 是如何解决循环依赖的?

    1.由同事抛的一个问题开始 最近项目组的一个同事遇到了一个问题,问我的意见,一下子引起的我的兴趣,因为这个问题我也是第一次遇到.平时自认为对spring循环依赖问题还是比较了解的,直到遇到这个和后面的 ...

  5. Spring三级缓存解决循环依赖问题详解

    spring三级缓存解决循环依赖问题详解 前言 这段时间阅读了spring IOC部分的源码.在学习过程中,自己有遇到过很多很问题,在上网查阅资料的时候,发现很难找到一份比较全面的解答.现在自己刚学习 ...

  6. Spring的getBean解决循环依赖

    Spring是如何解决循环依赖的? 通过三级缓存提前暴露对象解决的. 三级缓存存放了哪些对象信息? 一级缓存存放的是完整对象. 二级缓存存放的是那些属性还没赋值的对象. 三级缓存存放的是ObjectF ...

  7. Spring是如何解决循环依赖的?

    1.案发情况 @Service public class TestService1 {@Autowiredprivate TestService2 testService2;@Asyncpublic ...

  8. Spring IOC 如何解决循环依赖?

    前言 假设对象A.B 之间相互依赖,Spring IOC是如何解决A.B两个对象的实例化的?答案是三级缓存. 三级缓存 SpringIOC 通过三级缓存来解决循环依赖问题,三级缓存指的是三个Map: ...

  9. 框架源码专题:Spring是如何解决循环依赖的?

    文章目录 1.什么是循环依赖? 2.解决循环依赖思路 3. 使用了三级缓存还有什么问题?怎么解决的? 4. 手写伪代码解决缓存依赖 5. 二级缓存能否解决循环依赖,三级缓存存在的意义 6. Sprin ...

最新文章

  1. 机器学习中的优化方法小结
  2. 赠送24本Spring boot+cloud套书!看完炒老板鱿鱼!
  3. 外贸网站建设需要考虑的五大层面
  4. funny alphabet
  5. Codeforces Round #168 (Div. 2)---A. Lights Out
  6. 介绍一种Fiori标准应用的增强方式
  7. 小程序采用mvvm设计模式_滴滴重磅开源跨平台统一 MVVM 框架 Chameleon
  8. 集大成者 —— 荀子
  9. spring5.0学习笔记6
  10. 手机哪个软件可以远程控制服务器,手机远程有什么功能?手机远程协助软件哪个好?...
  11. html鼠标移动图片自动放大,当鼠标移动到图片上时跟随鼠标显示放大的图片效果...
  12. 信号处理电路整理(RC、运放、TTL)
  13. 学生的知识管理工具:有道云笔记、幕布和 Effie
  14. 4、如果体彩中了500万,我买房、买车、资助希望工程、去欧洲旅游;如果没中,我买下一期体彩,继续烧高香。
  15. 压力传感器的种类与工作原理
  16. 流程挖掘的价值:头部制造业千万级增长的底牌
  17. 大数据开发工程师考试分享
  18. 客观评价 增长趋势比 vite 还猛的 TailwindCSS
  19. 如何在阿里云以外的服务器上安装安骑士
  20. plsql登录报错:ORA-27101: shared memory realm does not exist 错误的处理

热门文章

  1. java list intersect_C#编程中两个List集合使用Intersect方法求交集
  2. intersect 相交 范围_Intersect(相交)
  3. 6、中小企业网络架构-防火墙基本配置
  4. python编程用什么软件-python开发工具有哪些(初学python用什么软件)
  5. 坚强的人:可以承受压力的品质是包容
  6. 【Django 学习笔记】1、基础概念和MVT架构
  7. Launcher启动流程及初始化
  8. qt将html加载到资源文件,web页面嵌入到Qt
  9. [渲染层网络层错误] Failed to load local image resource /uni_modules/uview-ui/components//static/icon/person.
  10. 服务端技术方案模板参考