问题:
被@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 注解。