set target type property for reference bean definition#5710
set target type property for reference bean definition#5710mercyblitz merged 1 commit intoapache:masterfrom
Conversation
Codecov Report
@@ Coverage Diff @@
## master #5710 +/- ##
============================================
- Coverage 61.42% 61.38% -0.05%
Complexity 491 491
============================================
Files 928 928
Lines 37997 37954 -43
Branches 5483 5452 -31
============================================
- Hits 23341 23297 -44
+ Misses 12129 12125 -4
- Partials 2527 2532 +5
Continue to review full report at Codecov.
|
|
这个commit会导致 sample失败:
在 2.7.5 里,会先执行spring 会 DubboBootstrap.start() ,然后会exporet services,然后会初始化InjvmProtocol ,再init ReferenceConfig 。 但在这个commit之后,spring直接执行了 init ReferenceConfig,然后因为没有 初始化 InjvmProtocol,然后找不到 provider 就会失败。 初步分析,原因可能是:
|
嗯,排查了一下,发现ReferenceBean提前初始化的问题是由于当设置TargetType后,会导致Spring在判断是否为FactoryBean为false,从而执行getBean方法,spring 关键代码: if (isFactoryBean(beanName)) {
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
getBean(beanName);
} 而在这个commit之前,由于没有设置TargetType,在Spring中会使用BeanDefinition的BeanClass作为TargetType类型,关键代码 protected Class<?> determineTargetType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
Class<?> targetType = mbd.getTargetType();
if (targetType == null) {
targetType = (mbd.getFactoryMethodName() != null ?
getTypeForFactoryMethod(beanName, mbd, typesToMatch) :
// 解析TagetType
resolveBeanClass(mbd, beanName, typesToMatch));
if (ObjectUtils.isEmpty(typesToMatch) || getTempClassLoader() == null) {
mbd.resolvedTargetType = targetType;
}
}
return targetType;
}
protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
throws CannotLoadBeanClassException {
try {
if (mbd.hasBeanClass()) {
// 直接获取BeanClass作为TargetType
return mbd.getBeanClass();
}
// more
}catch(Exception ex){
// catch exception
}
}因此当不设置TargetType时,由于ReferenceBean的BeanClass就是ReferenceBean本身,所以第一步的isFactoryBean判断为true,且后续的isEagerInit为false,因而不会调用getBean初始化ReferenceBean。 当前想到的解决方法是 |
|
RefernceBean本质上就是FactoryBean,你给他设定tagertType,逻辑上就不是FactoryBean,完全破坏了spring中本身结构,现在看解决方法是加lazy。是为了解决而解决么。从根源上就错了。 |
|
按照这样改了之后
|
|
这样改是错的,本质上没有解决问题 |
What is the purpose of the change
Set target type property of reference bean definition can avoid reference bean early initialization
when define reference bean in xml.
The reason is spring will try to create factory bean instance to look what factory bean create if spring can't get target type from bean definition.
Brief changelog
set target type property for reference bean definition when parse dubbo bean definition.