dubbo @Reference 註解注入原理

問題:

被@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 註解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章