如何用spring源码剖析spring bean循环依赖

发布时间:2021-12-28 15:04:25 作者:柒染
来源:亿速云 阅读:157

本篇文章给大家分享的是有关如何用spring源码剖析spring bean循环依赖,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

spring bean循环依赖

spring bean循环依赖应该是spring 源码中比较难的一块知识了,下面我们结合代码还有时序图,来进行分析,看下spring 是如何优雅的处理spring bean的循环依赖的。

什么是bean的循环依赖

我们都知道spring的IOC 和DI,它可以帮助我们创建对象,并且可以帮我们自动注入需要spring管理的对象。然后会存在一种这样的情况,在对象 A 中需要依赖 B,而在对象 B 中有又依赖 A,当然可以有更多的对象依赖,他们之间会组成了一个闭环,如下图 如何用spring源码剖析spring bean循环依赖 在spring 初始化bean A的时候发现bean A依赖于bean B,然后去实例化bean B,实例化bean B的时候又发现bean B依赖于bean A...,这样陷入了一个无限循环的过程中,最终可能会导致内存溢出。当然,这只是我们的一个设想,spring当然不会让这样的事情发生。spring提供一个很优雅的方式来帮我们解决了bean之间循环依赖的问题,通过引入三级缓存机制来解决。 另外再说一点,不是所有的循环依赖spring 都可以解决,以下两种方式spring也是无法解决的

在正式开始之前,我们再说下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);

下面我们结合代码来做进一步的分析

依赖代码

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 循环依赖的时序图,对于后面我们分析源码会有很大的帮助 原始文件可以从这里下载

如何用spring源码剖析spring bean循环依赖

ClassPathXmlApplicationContext.java

我们调用了ClassPathXmlApplicationContext的带参构造方法,最终调用了下面的构造。这里完成了三件事:

  1. super(parent)初始化父类

  2. setConfigLocations(configLocations)设置本地的配置信息

  3. 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(),这个方法做了一下操作

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.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的属性了。到这里 ,beanAbeanB就完成了他们整个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循环依赖,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注亿速云行业资讯频道。

推荐阅读:
  1. Spring 源码(八)循环依赖
  2. spring循环依赖策略解析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

spring spring bean

上一篇:如何分析Apache Struts2-052 漏洞分析预警

下一篇:如何进行Apache Struts2 S2-057漏洞分析

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》