如何用spring源码剖析springbean循环依赖
本篇文章给大家分享的是有关如何用spring源码剖析spring bean循环依赖,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。
成都创新互联公司是专业的昌宁网站建设公司,昌宁接单;提供做网站、网站制作,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行昌宁网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
spring bean循环依赖
spring bean循环依赖应该是spring 源码中比较难的一块知识了,下面我们结合代码还有时序图,来进行分析,看下spring 是如何优雅的处理spring bean的循环依赖的。
什么是bean的循环依赖
我们都知道spring的IOC 和DI,它可以帮助我们创建对象,并且可以帮我们自动注入需要spring管理的对象。然后会存在一种这样的情况,在对象 A 中需要依赖 B,而在对象 B 中有又依赖 A,当然可以有更多的对象依赖,他们之间会组成了一个闭环,如下图 在spring 初始化bean A的时候发现bean A依赖于bean B,然后去实例化bean B,实例化bean B的时候又发现bean B依赖于bean A...,这样陷入了一个无限循环的过程中,最终可能会导致内存溢出。当然,这只是我们的一个设想,spring当然不会让这样的事情发生。spring提供一个很优雅的方式来帮我们解决了bean之间循环依赖的问题,通过引入三级缓存机制来解决。 另外再说一点,不是所有的循环依赖spring 都可以解决,以下两种方式spring也是无法解决的
依赖是通过构造方法实现的
scope 为prototype,也就是原型的情况
在正式开始之前,我们再说下spring的三级缓存以及定义 先来看下代码中是如何定义的
/** Cache of singleton objects: bean name to bean instance. */ private final MapsingletonObjects = new ConcurrentHashMap<>(256); /** Cache of singleton factories: bean name to ObjectFactory. */ private final Map > singletonFactories = new HashMap<>(16); /** Cache of early singleton objects: bean name to bean instance. */ private final Map 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来进行管理
测试代码
使用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的带参构造方法,最终调用了下面的构造。这里完成了三件事:
super(parent)
初始化父类setConfigLocations(configLocations)
设置本地的配置信息refresh()
完成spring容器的初始化
这里我们重点观察第三个方法,因为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()
,这个方法做了一下操作
初始化所有剩下的非懒加载的单例bean
初始化创建非懒加载方式的单例Bean实例(未设置属性)
填充属性
初始化方法调用(比如调用afterPropertiesSet方法、init-method方法)
调用BeanPostProcessor(后置处理器)对实例bean进行后置处理 所以我们接下来看下这个方法
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的名字 ListbeanNames = 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 ) ((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
开始处理循环依赖
为了方便阅读删除了部分源码
上面方法中调用了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); } protectedT doGetBean(final String name, @Nullable final Class 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.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)); } //... 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循环依赖,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注创新互联行业资讯频道。
当前文章:如何用spring源码剖析springbean循环依赖
本文来源:http://myzitong.com/article/gospij.html