admin管理员组文章数量:1567290
一 循环依赖问题
最近在项目中遇到如下异常
Bean with name ‘departmentServiceImpl’ has been injected into other beans [userServiceImpl] 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.
代码如下:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private DepartmentService departmentService;
}
@Service
public class DepartmentServiceImpl implements DepartmentService {
@Autowired
private UserService userService;
}
如果是这样引入,Spring会自己解决循环依赖。但是我对 DepartmentServiceImpl 进行了 后置处理器BeanPostProcessor 产生了一个 动态代理对象:
@Component
public class CustomPostProccessorr implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (Objects.equals(beanName,"departmentServiceImpl")) {
return Proxy.newProxyInstance(CustomPostProccessorr.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(bean, args);
}
});
}
return bean;
}
}
于是就出现了上面的异常。
二 产生问题的原因
1 三级缓存
Spring在解决bean的循环时,使用了三级缓存
1.1 一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
存放已经创建好的单例bean。
1.2 二级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
存放所有属性还未赋值完的bean或者bean的代理对象。
1.3 三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
三级缓存存放的是如下 接口的
@FunctionalInterface
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
存放到singletonFactories
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
getEarlyBeanReference 方法
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
这里是对创建的bean进行包装。获取spring容器中实现了 SmartInstantiationAwareBeanPostProcessor 接口的类,调用 getEarlyBeanReference 方法,对bean进行一系列处理,如: 产生代理对象 。如果不进行处理,直接就返回bean对象本身。
2 获取缓存bean
bean在创建之前,首先会去容器中获取缓存的bean,获取bean的代码如下:
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 从一级缓存中获取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 从二级缓存中获取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 获取三级缓存中的 ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 调用 ObjectFactory的 getObject 方法,获取包装的bean或者bean本身。
singletonObject = singletonFactory.getObject();
// 把包装的bean或者bean放入到二级缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
// 删除三级缓存中 bean对应的 ObjectFactory
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
如果没有循环依赖,创建一个bean调用该方法时,this.singletonFactories.get(beanName); 肯定返回的是 null
,因为一个bean对应的三级缓存中的ObjectFactory是在bean内存分配完成,还未对属性进行赋值之前加入到三级缓存中的。如下:
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);
}
// 创建bean
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.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 设置bean对应的三级缓存中的 ObjectFactory
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 为 bean中的属性赋值
populateBean(beanName, mbd, instanceWrapper);
/**
* 初始化bean, 包括
* 1. 对bean进行Aware接口的注入,
* 2. @PostConstruct 标注的方法初始化,
* 3. 调用spring 容器中 实现了 BeanPostProcessor 类的 postProcessBeforeInitialization 方法
* 4. 实现了 InitializingBean ,调用 afterPropertiesSet 方法
* 5. 如果使用了 xml,调用 bean标签中 init-method 标注的类
* 6. 调用spring 容器中 实现了 BeanPostProcessor 类的 postProcessAfterInitialization 方法
*/
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
}
}
如果this.singletonFactories.get(beanName); 的返回的不是 null ,则说明现在有循环依赖了,获取ObjectFactory,调用getObject 方法,获取经过 spring 容器中 SmartInstantiationAwareBeanPostProcessor 类处理过后的bean,放入到二级缓存中,删除三级缓存中的ObjectFactory。
3. 循环bean创建过程
- (1) 创建 DepartmentServiceImpl, 分配完内存,在三级缓存singletonFactories中设置 bean的三级缓存ObjectFacotory,再进行属性赋值时发现依赖UserService。
- (2) 创建 UserServiceImpl , 分配完内存,在三级缓存singletonFactories中设置 bean的三级缓存ObjectFacotory,再进行属性赋值时发现依赖DepartmentService。
- (3) 创建 DepartmentServiceImpl 调用 getSingleton 获取缓存的bean时,发现有对应的三级缓存,走 this.singletonFactories.get(beanName); 不为 null的逻辑,把包装的bean放入到二级缓存中,同时返回包装的bean,对 UserServiceImpl 对象中的 DepartmentService 属性赋值,之后 UserServiceImpl 创建完成。
- (4) 再对 DepartmentServiceImpl 中的属性使用spring 容器中已经创建完成的UserServiceImpl 对 UserService 赋值,之后完成 DepartmentServiceImpl 的创建。
以上是有循环依赖时spring创建bean的过程。但是为什么对 DepartmentService添加了一个 BeanPostProcessor 之后,会有开头的异常呢?看如下在bean初始化完成之后的代码:
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 为属性赋值
populateBean(beanName, mbd, instanceWrapper);
/**
* 初始化bean, 包括
* 1. 对bean进行Aware接口的注入,
* 2. @PostConstruct 标注的方法初始化,
* 3. 调用spring 容器中 实现了 BeanPostProcessor 类的 postProcessBeforeInitialization 方法
* 4. 实现了 InitializingBean ,调用 afterPropertiesSet 方法
* 5. 如果使用了 xml,调用 bean标签中 init-method 标注的类
* 6. 调用spring 容器中 实现了 BeanPostProcessor 类的 postProcessAfterInitialization 方法
*/
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
// 获取在二级缓存中引用的bean
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 判断在初始化过程中是否创建了代理对象
if (exposedObject == bean) {
// 没有创建代理对象,直接使用bean返回
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
// 获取有依赖的bean
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
// 有依赖的bean,则直接抛异常
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.");
}
}
}
如果在初始化过程中,对bean进行了替换,如创建了代理对象。就会使得 exposedObject == bean 不成立, 并且在bean创建过程中有循环依赖,就会抛 BeanCurrentlyInCreationException 异常。spring 在这里抛异常的原因是:
bean在创建过程中,循环依赖另外一个bean,而另外一个bean中引用了未初始化之前的当前bean。如果在初始化的时候对当前bean进行了替换,就会导致循环依赖的另外一个bean引用的当前bean与容器中的当前bean不一致,一个是替换之前的bean,一个是替换之后的bean。
三 问题的解决
之所以会触发这个异常,就是因为我们在为循环依赖的另外一个bean的当前引用赋值时使用的是原始的bean,可以把对bean的包装放在这个赋值之前,这时,我们再来看 三级缓存的第三级缓存,其实就是给我们机会,对bean进行包装,处理,默认spring不做任何处理。把代码改成如下方式,可以解决为departmentServiceImpl创建代理对象的问题 :
@Component
public class CustomSmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
if (Objects.equals(beanName,"departmentServiceImpl")) {
return Proxy.newProxyInstance(CustomPostProccessorr.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(bean, args);
}
});
}
return bean;
}
}
本文标签: 异常SpringBeanPostProcessor
版权声明:本文标题:spring中BeanPostProcessor引发的循环依赖异常 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dianzi/1726872604a1087996.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论