如何手动关闭spring的循环依赖

了解过spring的小伙伴应该都知道spring默认是支持循环依赖的,那么我们怎么手动关闭spring的循环依赖呢?

话不多说,先看源码:

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.
		//判断是否允许循环依赖
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			//第四次调用后置处理器,判断是否需要aop
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
        //省略后面代码
}

初始化断点调试进来我们看到这里判断是否支持循环依赖是根据 allowCircularReferences这个布尔值来决定的。

/** Whether to automatically try to resolve circular references between beans */
	private boolean allowCircularReferences = true;

可以看到spring默认这个属性是为true的,那么我们如何修改这个属性值呢?

我们看到当前方法是属于AbstractAutowireCapableBeanFactory这个类的,这个类一看就知道是一个BeanFactory对象,其实如果我们可以修改spring源码的话,在容器初始化之前,也就是refresh方法执行之前,我们可以加这样一行代码修改这个值的属性来关闭循环依赖:

setAllowCircularReferences(false);
/**
	 * Create a new AnnotationConfigApplicationContext, deriving bean definitions
	 * from the given annotated classes and automatically refreshing the context.
	 * @param annotatedClasses one or more annotated classes,
	 * e.g. {@link Configuration @Configuration} classes
	 */
	public AnnotationConfigApplicationContext(Class... annotatedClasses) {
		//这里由于他有父类,故而回先调用父类的构造方法,然后才会调用自己的
		//在自己的构造方法中初始一个读取器和扫描器
		//beanFactory
		this();
		setAllowCircularReferences(false);//关闭spring对循环依赖的支持
		//annotatedClasses初始化传过来的appconfig类,加载类。register的作用就是把它也加入到bean工厂中
		//ac.register(Appconfig.class)
		//this.beanDefinitionMap.put(beanName,beanDefinition)
		register(annotatedClasses);
		refresh();
	}

可以看到这个方法内部就是调用BeanFactory来修改这个属性值:

此外spring提供了api来供我们获取beanfactory,我们可以在容器刷新前调用:

public static void main(String[] args) {
		AnnotationConfigApplicationContext ac =
				new AnnotationConfigApplicationContext();

		AbstractAutowireCapableBeanFactory beanFactory = (AbstractAutowireCapableBeanFactory) ac.getBeanFactory();
		beanFactory.setAllowCircularReferences(false);
		ac.register(AppConfig.class);
		ac.refresh();

		System.out.println(ac.getBean("city"));
	}

以上,感谢阅读。

你可能感兴趣的:(源码解析,spring,源码,循环依赖,ioc容器)