[Spring] study notes seven circular dependency Solutions


This chapter we mainly talk about the doCreateBean() process, how `spring is to resolve circular dependencies, and some use the wrong way.

problem

Suppose now that we have two classes, namely, Aclass, Bclass, and Aclass need to refer to Bthe class, Bthe class need to refer to Athe class, which is a set of baby mode.

@Component
public class A {
  @Autowired
  private B b;
}

@Component
public class B {
  @Autowired
  private A a;
}

So how Spring handle this situation?
Here we revisit spring-loaded process for the bean.

存在
不存在
在BeanFactory中获取Bean
是否存在Bean
返回Bean
创建Bean

solution

In fact, out in front of the loading process solution is very simple, as long as 填充Bean属性between the directly into BeanFactorythe can, so back to the current dependence bean can be taken directly from the BeanFactory, and then return to go out, do not go in creation bean process.

Here we look at the perspective of Bean is how to solve.

创建A实例
将A实例添加到BeanFactory
填充A属性触发创建B实例
创建B实例
填充B属性触发创建A实例
在BeanFactory中获取到A实例

This jumped out of the cycle of death has been created.

Non-normal performance

Read the above solutions whether they think it'll be safe? You can rest assured the bold circular dependencies Bean?

Here we look at an example, it is based on the above two categories, only some small change.

@Component
public class A {
  @Autowired
  private B b;
  @Async
  public void async(){}
}

@Component
public class B {
  @Autowired
  private A a;
  @Async
  public void async(){}
}

We're just a way to add an annotation @Async, then the situation will be changed dramatically.

Being given
Then given a circular dependencies, wherein the bean warpper used.

Not to say that the good has been solved circular dependencies thing? How reported this error?

This @Asyncannotation in the end is what demons.

We first take a look at this place which is wrong in the end thrown out.

The following code occurs after Bean created.

		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.");
					}
				}
			}
		}

Or go step by step

  1. The first step to get through to the original Bean BeanFactory
  2. The second step, Bean and Bean retrieved to determine whether the creation of the same (important ... some students hitting on yet?), The same as the direct return Bean created
  3. The third step, if allowed to inject wrappingBean current internal and Bean have dependence, and dependence has been used, it throws the above error.

If the general case, we will direct return in the second step, since the original Bean and Bean we have created is exactly the same. (That is, no @Asynccomment when the idea came up thing?)

I thought then, in turn, use the @Asyncannotation will lead us to create the Bean and from BeanFactoryinconsistencies in to get the original Bean.

why?

First @Asyncannotation function is to convert the synchronous operation of the asynchronous operation, then how to achieve it without intrusion? Acting right. so, Bean to create a proxy class is returned. It is not the same.

So long as the annotations that could be proxied Bean, it will cause this problem. (Circular dependencies)

solution

So how to solve it?

@LazyNotes, since the spring @Lazywill determine the conditions can not be reached and skip detection.

else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) 

That is, this.allowRawInjectionDespiteWrappingthe value becomes true.

Because the @Lazynotes is returned proxy Bean, so let this Spring Bean skip this test.

Example:

@Component
public class A {

  @Autowired
  @Lazy
  private B b;

  @Async
  public void async(){}

}

@Component
public class B {

  @Autowired
  @Lazy
  private A a;

  @Async
  public void async(){}

}
Released nine original articles · won praise 0 · Views 119

Guess you like

Origin blog.csdn.net/qq_18300037/article/details/104076902