問題:
被@Reference 註解的 bean,是在什麼時機注入的?
被@Reference 註解的 bean,通常是一個接口,怎麼可以被實例化呢?
答案是:
@Reference 的注入時機和 @Autowired 註解是類似的,但不完全一樣。負責修飾 bean 屬性的 BeanFactoryPostProcessor不同。
@Reference修飾的域是通過動態代理實現的。也就是生成了一個動態的接口實現類。
在github上https://github.com/alibaba/dubbo-spring-boot-starter下載了dubbo-spring-boot-starter
在spring.factories文件中找到DubboConsumerAutoConfiguration類
@Configuration
@ConditionalOnClass(Service.class)
@ConditionalOnBean(annotation = EnableDubboConfiguration.class)
@AutoConfigureAfter(DubboAutoConfiguration.class)
@EnableConfigurationProperties(DubboProperties.class)
public class DubboConsumerAutoConfiguration extends DubboCommonAutoConfiguration {
private static final Map<ClassIdBean, Object> DUBBO_REFERENCES_MAP =
new ConcurrentHashMap<ClassIdBean, Object>();
@Autowired
private ApplicationContext applicationContext;
@Autowired
private DubboProperties properties;
public static Object getDubboReference(ClassIdBean classIdBean) {
return DUBBO_REFERENCES_MAP.get(classIdBean);
}
@Bean
public BeanPostProcessor beanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
Class<?> objClz;
if (AopUtils.isAopProxy(bean)) {
objClz = AopUtils.getTargetClass(bean);
} else {
objClz = bean.getClass();
}
try {
for (Field field : objClz.getDeclaredFields()) {
//判斷該字段是否有 Reference 註解
Reference reference = field.getAnnotation(Reference.class);
if (reference != null) {
DubboConsumerAutoConfiguration.this
.initIdConfigMap(DubboConsumerAutoConfiguration.this.properties);
ReferenceBean<?> referenceBean =
DubboConsumerAutoConfiguration.this.getConsumerBean(beanName, field, reference);
Class<?> interfaceClass = referenceBean.getInterfaceClass();
String group = referenceBean.getGroup();
String version = referenceBean.getVersion();
ClassIdBean classIdBean = new ClassIdBean(interfaceClass, group, version);
Object dubboReference =
DubboConsumerAutoConfiguration.DUBBO_REFERENCES_MAP.get(classIdBean);
if (dubboReference == null) {
synchronized (this) {
// double check
dubboReference =
DubboConsumerAutoConfiguration.DUBBO_REFERENCES_MAP.get(classIdBean);
if (dubboReference == null) {
referenceBean.afterPropertiesSet();
// dubboReference should not be null, otherwise it will cause
// NullPointerException
//獲取 dubbo reference,也就是代理類
dubboReference = referenceBean.getObject();
DubboConsumerAutoConfiguration.DUBBO_REFERENCES_MAP.put(classIdBean,
dubboReference);
}
}
}
field.setAccessible(true);
field.set(bean, dubboReference);
}
}
} catch (Exception e) {
throw new BeanCreationException(beanName, e);
}
return bean;
}
...
}
ReferenceBean 的getObject()方法就是進入到ReferenceBean 類中,和xml配置就是相同的了
注意點:
new BeanPostProcessor(){重寫postProcessBeforeInitialization方法},在spring 容器中註冊bean後,會自動應用在容器中。在所有Bean實例化之後進行判斷其屬性字段上是否有 @Reference 註解。