本篇文章给大家分享的是有关如何用spring源码剖析spring bean循环依赖,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。
spring bean循环依赖
spring bean循环依赖应该是spring 源码中比较难的一块知识了,下面我们结合代码还有时序图,来进行分析,看下spring 是如何优雅的处理spring bean的循环依赖的。
什么是bean的循环依赖
我们都知道spring的IOC 和DI,它可以帮助我们创建对象,并且可以帮我们自动注入需要spring管理的对象。然后会存在一种这样的情况,在对象 A 中需要依赖 B,而在对象 B 中有又依赖 A,当然可以有更多的对象依赖,他们之间会组成了一个闭环,如下图
在正式开始之前,我们再说下spring的三级缓存以及定义 先来看下代码中是如何定义的
/** Cache of singleton objects: bean name to bean instance. */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** Cache of singleton factories: bean name to ObjectFactory. */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); /** Cache of early singleton objects: bean name to bean instance. */ private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
singletonObjects 一级缓存, 用于存放完全初始化之后的bean,也就是说,所有的准备工作已经完成了,可以拿出来使用了
earlySingletonObjects 二级缓存,存放原始的bean对象,这时候bean只是实例化完成,还没有进行属性设置等工作
singletonFactories 三级缓存,存放只是实例化,还没有进行其它任何操作的bean对象
下面我们结合代码来做进一步的分析
依赖代码
bean A
创建类BeanA,然后通过set注入BeanB
public class BeanA { private BeanB beanB; public void setBeanB(BeanB beanB) { this.beanB = beanB; } }
bean B
创建类BeanB,然后通过set注入BeanA
public class BeanB { private BeanA beanA; public void setBeanA(BeanA beanA) { this.beanA = beanA; } }
配置文件applicationContext.xml
将BeanA 和BeanB 交给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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--循环依赖问题--> <bean id="beanA" class="com.lagou.test.BeanA"> <property name="beanB" ref="beanB"/> </bean> <bean id="beanB" class="com.lagou.test.BeanB"> <property name="beanA" ref="beanA"/> </bean> </beans>
测试代码
使用ClasspathXmlApplicationContext
来初始化bean
public class BeanTest { public static void main(String[] args) { ClasspathXmlApplicationContext applicationContext = new ClasspathXmlApplicationContext("classpath:applicationContext.xml"); Object beanA = applicationContext.getBean("beanA"); System.out.println(beanA); } }
源码分析
循环依赖时序图
在分析源码前我们先来看下spring 循环依赖的时序图,对于后面我们分析源码会有很大的帮助 原始文件可以从这里下载
ClasspathXmlApplicationContext.java
我们调用了ClasspathXmlApplicationContext的带参构造方法,最终调用了下面的构造。这里完成了三件事:
这里我们重点观察第三个方法,因为spring bean的初始化是在这里完成的
public ClasspathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { // 初始化父类 super(parent); // 设置本地的配置信息 setConfigLocations(configLocations); // 完成spring容器的初始化 if (refresh) { refresh(); } }
AbstractApplicationContext.java
上面说了,refresh方法是初始化spring容器的,所以这是一个核心方法。这里面包含beanfactory 和bean的初始化操作,因为方法比较多,对每个方法都进行了注释,不一一赘述了,这里我们重点关注finishbeanfactoryInitialization()
,这个方法做了一下操作
public void refresh() throws BeansException, IllegalStateException { // 对象锁加锁 synchronized (this.startupShutdownMonitor) { //刷新前的预处理,表示在真正做refresh操作之前需要准备做的事情: prepareRefresh(); /* 获取beanfactory;默认实现是DefaultListablebeanfactory 加载BeanDefition 并注册到 BeanDefitionRegistry */ ConfigurableListablebeanfactory beanfactory = obtainFreshbeanfactory(); //beanfactory的预准备工作(beanfactory进行一些设置,比如context的类加载器等) preparebeanfactory(beanfactory); try { //beanfactory准备工作完成后进行的后置处理工作 postProcessbeanfactory(beanfactory); //实例化实现了beanfactoryPostProcessor接口的Bean,并调用接口方法 invokebeanfactoryPostProcessors(beanfactory); //注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执行 registerBeanPostProcessors(beanfactory); //初始化MessageSource组件(做国际化功能;消息绑定,消息解析); initMessageSource(); //初始化事件派发器 initApplicationEventMulticaster(); //子类重写这个方法,在容器刷新的时候可以自定义逻辑;如创建Tomcat,Jetty等WEB服务器 onRefresh(); //注册应用的监听器。就是注册实现了ApplicationListener接口的监听器bean registerListeners(); /* Instantiate all remaining (non-lazy-init) singletons. 初始化所有剩下的非懒加载的单例bean 初始化创建非懒加载方式的单例Bean实例(未设置属性) 填充属性 初始化方法调用(比如调用afterPropertiesSet方法、init-method方法) 调用BeanPostProcessor(后置处理器)对实例bean进行后置处理 */ finishbeanfactoryInitialization(beanfactory); //完成context的刷新。主要是调用LifecycleProcessor的onRefresh()方法,并且发布事件(ContextRefreshedEvent) finishRefresh(); } catch (BeansException ex) { destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } }
这个方法的最后调用了beanfactory的preInstantiateSingletons()
方法,接下继续跟踪preInstantiateSingletons()
方法
protected void finishbeanfactoryInitialization(ConfigurableListablebeanfactory beanfactory) { 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)); } 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(); }
DefaultListablebeanfactory.java
preInstantiateSingletons()
中获取了所有需要spring管理的bean的name,然后需要遍历,进行bean的创建,核心方法是getBean(beanName)
,根据获取到的bean name进行bean的初始化,所以接下来我们跟踪getBean(beanName)
public void preInstantiateSingletons() throws BeansException { if (logger.isTraceEnabled()) { logger.trace("Pre-instantiating singletons in " + this); } // 获取所有bean的名字 List<String> beanNames = new ArrayList<>(this.beanDeFinitionNames); // 触发所有非延迟加载单例bean的初始化,主要步骤为getBean for (String beanName : beanNames) { RootBeanDeFinition bd = getMergedLocalBeanDeFinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isfactorybean(beanName)) { Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); // 如果是factorybean则加& 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 { // 实例化当前bean getBean(beanName); } } } 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(); } } } }
开始处理循环依赖
为了方便阅读删除了部分源码
上面方法中调用了getBean()
,getBean()
又调用了doGetBean()
,经过前面的铺垫,其实到这里,才开始了真正的循环依赖相关的源码逻辑。 之前我们说过spring 的三级缓存,这里根据bean name先调用getSingleton(beanName)
方法,getSingleton(beanName)
方法中又调用了它的重载方法。我们先假设要去找的bean为beanA,spring先从一级缓存中去找我们要的beanA,找不到的话去二级缓存中去找,二级缓存还找不到去一级缓存中去拿,当然,因为刚加载,所以三级缓存中也是没有的。所以代码继续往下执行。
public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 解析beanName 如果以&开头去掉&开头,如果是别名获取到真正的名字 final String beanName = transformedBeanName(name); // 尝试从一二三级缓存中获取 bean Object sharedInstance = getSingleton(beanName); // 如果已经存在则返回 if (sharedInstance != null && args == null) { // 针对 factorybean 的处理 bean = getobjectForBeanInstance(sharedInstance, name, beanName, null); } else { // 如果是prototype类型且开启允许循环依赖,则抛出异常 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } try { final RootBeanDeFinition mbd = getMergedLocalBeanDeFinition(beanName) // 创建单例bean if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { // 创建 bean return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); bean = getobjectForBeanInstance(sharedInstance, name, beanName, mbd); } } } return (T) bean; } public Object getSingleton(String beanName) { return getSingleton(beanName, true); } protected Object getSingleton(String beanName, boolean allowEarlyReference) { //先从一级缓存singletonObjects中拿 Object singletonObject = this.singletonObjects.get(beanName); // isSingletonCurrentlyInCreation(beanName)判断当前单例bean是否正在创建中 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { //一级缓存没有从二级缓存earlySingletonObjects中去拿 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { //二级缓存没有从三级缓存singletonFactories去拿 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getobject(); //三级缓存中有的话放入二级缓存中,同时从一级缓存中删除 this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }
接着上面的doGetBean()
方法往下走,又调用了getSingleton()
的另一个重载方法,可以看到第二个参数是一个ObjectFactory接口,而这里spring采用了一个lambda表达式来实现了getobject()方法。调用传进来的lambda表达式singletonFactory.getobject(),进行bean的创建。
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正在被创建,因为spingbean创建过程复杂,步骤很多,需要标识 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 传进来的调用,lamda表达式使用 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; } }
接下来看下lambda表达式中的createBean(beanName, mbd, args)
方法是如何实现的 createBean()
中其实又调用了doCreateBean()
,它才是真正干活的。这里首先调用对createBeanInstance(beanName, mbd, args)
对beanA进行实例化,然后放入三级缓存中,接下来调用populateBean(beanName, mbd, instanceWrapper)
对beanA进行属性填充,在我们这里其实就是填充beanB,我们继续看填充方法中做了什么
protected Object createBean(String beanName, RootBeanDeFinition mbd, @Nullable Object[] args) throws BeanCreationException { // 拿到Bd RootBeanDeFinition mbdToUse = mbd; //.... try { // 进入,真真正正创建bean Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { throw ex; } } 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) { // 创建 Bean 实例,仅仅调用构造方法,但是尚未设置属性 instanceWrapper = createBeanInstance(beanName, mbd, args); } boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCir@R_404_6103@rReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential cir@R_404_6103@r references"); } addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } //... Object exposedobject = bean; try { // Bean属性填充 populateBean(beanName, mbd, instanceWrapper); // 调用初始化方法,应用BeanPostProcessor后置处理器 exposedobject = initializeBean(beanName, exposedobject, mbd); } //... return exposedobject; }
populateBean()
中最后调用了applyPropertyValues(beanName, mbd, bw, pvs)
,applyPropertyValues(beanName, mbd, bw, pvs)
方法中有调用了resolveValueIfNecessary(pv, originalValue)
,resolveValueIfNecessary(pv, originalValue)
中又调用了resolveReference(argName, ref)
,好了终于到重要关头了,在resolveReference(argName, ref)
中我们可用看到,又调用了getBean(refName)
方法,获取beanB。呀,这是什么情况,怎么又回到起点了?哈哈,别着急,我们继续分析。 既然调用了getBean()
方法,我们不妨在回头看看(代码我就不再贴一遍了)。 getBean()
继续调用doGetBean()
方法,然后继续调用getSingleton()
方法去缓存中拿beanB,然后发现beanB也不再缓存中,然后就开始去创建beanB。创建beanB先进行实例化,然后放入到缓存中,之后再调用populateBean()
进行属性填充(其实就是填充依赖beanA),之前我们提到beanA,在实例化beanB之前已经实例化完成并放入到三级缓存中了,这里我们就可以使用了,虽然还是个娃娃,但是够用了。到这里beanB属性填充之后就可以长大,成为完成的bean了。这时候将beanB放入到缓存池中,我们就可以回过头来填充beanA的属性了。到这里 ,beanA、beanB就完成了他们整个bean的创建过程了。
protected void populateBean(String beanName, RootBeanDeFinition mbd, @Nullable BeanWrapper bw) { //... if (pvs != null) { applyPropertyValues(beanName, mbd, bw, pvs); } } protected void applyPropertyValues(String beanName, BeanDeFinition mbd, BeanWrapper bw, PropertyValues pvs) { //... for (PropertyValue pv : original) { if (pv.isConverted()) { deepcopy.add(pv); } else { String propertyName = pv.getName(); Object originalValue = pv.getValue(); // Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); Object convertedValue = resolvedValue; //... } } //... } public Object resolveValueIfNecessary(Object argName, @Nullable Object value) { if (value instanceof RuntimeBeanReference) { RuntimeBeanReference ref = (RuntimeBeanReference) value; return resolveReference(argName, ref); } //... } private Object resolveReference(Object argName, RuntimeBeanReference ref) { try { Object bean; String refName = ref.getBeanName(); refName = String.valueOf(doEvaluate(refName)); if (ref.isToParent()) { bean = this.beanfactory.getParentbeanfactory().getBean(refName); } else { bean = this.beanfactory.getBean(refName); this.beanfactory.registerDependentBean(refName, this.beanName); } if (bean instanceof NullBean) { bean = null; } return bean; } catch (BeansException ex) {}
以上就是如何用spring源码剖析spring bean循环依赖,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注编程之家行业资讯频道。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。