Dubbo源碼之Spring整合

本文主要介紹了在不同的配置模式下,dubbo與spring整合的原理,即:xml配置、注解配置、自動(dòng)化配置 三種模式下的配置生效原理。

XML啟動(dòng)

Schema擴(kuò)展機(jī)制

Spring提供了 Schema 擴(kuò)展機(jī)制,用戶可以自定義 Schema 文件,并自定義 Schema 解析器,然后集成到SpringIOC容器中。
創(chuàng)建自定義擴(kuò)展,主要有以下步驟:

  1. 創(chuàng)建 Schema 文件,描述自定義的合法構(gòu)建模塊,也就是xsd文件,主要用于定義數(shù)據(jù)約束;
  2. 自定義個(gè)處理器類,并實(shí)現(xiàn)NamespaceHandler接口,在里面注冊(cè)各個(gè)標(biāo)簽對(duì)應(yīng)的BeanDefinitionParser;
  3. 自定義一個(gè)或多個(gè)解析器,實(shí)現(xiàn) BeanDefinitionParser 接口,用于定義Bean的解析邏輯;

解析流程

有關(guān)于 Spring 對(duì)這部分內(nèi)容的實(shí)現(xiàn)細(xì)節(jié),可以參考 Schema解析,下面我對(duì)這部分內(nèi)容做一個(gè)簡(jiǎn)單的梳理:

  1. Spring 中對(duì)Bean的解析主要是通過 DefaultBeanDefinitionDocumentReader#parseBeanDefinitions 方法,具體的解析邏輯委托給 BeanDefinitionParserDelegate 進(jìn)行;
  2. DefaultBeanDefinitionDocumentReader#parseBeanDefinitions 會(huì)區(qū)分 默認(rèn)的Namespace和自定義的Namesapce(除Spring的一些默認(rèn)標(biāo)簽外,其它的都是自定義Namespace)
  3. 在解析自定義Namespace的時(shí)候會(huì)調(diào)用 DefaultNamespaceHandlerResolver#resolve 方法, DefaultNamespaceHandlerResolver 中會(huì)加載所有 META-INF/spring.handlers 文件里面的內(nèi)容,然后維護(hù)一套 NamespaceURL => NamespaceHandler 的映射關(guān)系。然后在 DefaultNamespaceHandlerResolver#resolve 方法中調(diào)用 當(dāng)前NamespaceURL對(duì)應(yīng)的 NamespaceHandler#init 方法。
  4. dubbo對(duì)應(yīng)的 NamespaceHandler 是 DubboNamespaceHandler,在 DubboNamespaceHandler#init 方法中,會(huì)找到各個(gè)標(biāo)簽對(duì)應(yīng)的 BeanDefinitionParser 接口,這里對(duì)應(yīng) DubboBeanDefinitionParser 并緩存起來;
  5. 在解析標(biāo)簽的時(shí)候會(huì)調(diào)用 DubboNamespaceHandler#parse 方法,而真正的解析邏輯委托給內(nèi)部的 DubboBeanDefinitionParser#parse 方法;

補(bǔ)充部分關(guān)鍵代碼:

// DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                if (delegate.isDefaultNamespace(ele)) {
                    // 默認(rèn)解析
                    parseDefaultElement(ele, delegate);
                }else {
                    // 自定義解析
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        // 自定義解析
        delegate.parseCustomElement(root);
    }
}
// DubboNamespaceHandler.java
// NamespaceHandlerSupport是一個(gè)抽象類,實(shí)現(xiàn)了NamespaceHandler接口
public class DubboNamespaceHandler extends NamespaceHandlerSupport {

    static {
        Version.checkDuplicate(DubboNamespaceHandler.class);
    }

    @Override
    public void init() {
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
    }

}

至此,整個(gè)dubbo的xml標(biāo)簽解析流程就非常清晰了,如果你想通過XML配置的方式來使用dubbo,那么當(dāng)你配置好xml之后,隨著 Spring 的啟動(dòng),就會(huì)自動(dòng)解析dubbo對(duì)應(yīng)的那些標(biāo)簽了。

注解啟動(dòng)

注解是為了讓我們擺脫繁瑣的XML配置,但對(duì)代碼有一定侵入,高版本的dubbo和springboot整合其實(shí)非常方便,引入依賴之后只需要在啟動(dòng)類上添加 @EnableDubbo 注解即可。以 dubbo 2.7.2springboot 2.1.4.RELEASE 為例:

使用示例

依賴

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-web'

    implementation 'org.apache.dubbo:dubbo:2.7.2'
    implementation 'org.apache.dubbo:dubbo-registry-zookeeper:2.7.2'
    implementation 'org.apache.dubbo:dubbo-metadata-report-zookeeper:2.7.2'

    implementation 'org.apache.zookeeper:zookeeper:3.4.12'
    implementation 'org.apache.curator:curator-recipes:2.12.0'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

啟動(dòng)類


@SpringBootApplication
@EnableDubbo
public class SDubboApplication {

    public static void main(String[] args) {
        SpringApplication.run(SDubboApplication.class, args);
    }

    @Configuration
    @PropertySource("classpath:/dubbo-provider.properties")
    static class ProviderConfiguration {
        @Bean
        public RegistryConfig registryConfig() {
            RegistryConfig registryConfig = new RegistryConfig();
            registryConfig.setAddress("zookeeper://10.9.44.133:2181");

            // 注冊(cè)簡(jiǎn)化版的的url到注冊(cè)中心
            registryConfig.setSimplified(true);
            return registryConfig;
        }

        @Bean
        public MetadataReportConfig metadataReportConfig() {
            MetadataReportConfig metadataReportConfig = new MetadataReportConfig();
            metadataReportConfig.setAddress("zookeeper://10.9.44.133:2181");
            return metadataReportConfig;
        }

        @Bean
        public ConfigCenterConfig configCenterConfig() {
            ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();
            configCenterConfig.setAddress("zookeeper://10.9.44.133:2181");
            return configCenterConfig;
        }
    }

}

dubbo-provider.properties

dubbo.application.name=sdubbo
dubbo.protocol.name=dubbo
dubbo.protocol.port=20882

有關(guān)于通過注解定義Provider和Consumer這里就不介紹了。從上面的代碼中可以看到,那三個(gè)Bean只是一些配置工作,這不是我們關(guān)注的重點(diǎn),重點(diǎn)在 @EnableDubbo 注解,為什么添加這個(gè)注解之后dubbo服務(wù)就自動(dòng)注冊(cè)了?

@EnableDubbo

不妨先看看這個(gè)注解,可以發(fā)現(xiàn)它引用了 @EnableDubboConfig@DubboComponentScan ,前者與配置相關(guān),后者與 服務(wù)注冊(cè)和服務(wù)引用相關(guān)。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
......
}

@EnableDubboConfig

這個(gè)注解和 外部化配置相關(guān) ,可以參考一篇博文: 外部化配置

即:一些通用的配置信息全部配置在 application.properties 或者 bootstrap.properties 配置文件中,dubbo會(huì)根據(jù)這些配置信息自動(dòng)創(chuàng)建 ApplicationConfigRegistryConfigProviderConfig 等Bean,而不需要我們通過注解的方式硬編碼去創(chuàng)建。

其核心原理在 DubboConfigConfigurationRegistrar 類中,這個(gè)不是本篇文章的重點(diǎn),不過多介紹。

其實(shí)在上面的示例中,就已經(jīng)用到了外部化配置特性,雖然沒有在 application.yaml 中定義dubbo的這些屬性,但是在注解類中通過 @PropertySource("classpath:/dubbo-provider.properties") 將這些屬性導(dǎo)入進(jìn)來了,所以dubbo會(huì)自動(dòng)根據(jù)這些屬性去創(chuàng)建相應(yīng)的Bean, 比如ApplicationConfig,雖然在示例中沒有通過硬編碼的方式創(chuàng)建ApplicationConfig,但是dubbo在讀到 dubbo-provider.properties 文件中的 dubbo.application 屬性時(shí)會(huì)自動(dòng)創(chuàng)建一個(gè) ApplicationConfig

外部化配置下,dubbo和springboot整合如下:

依賴

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-web'

    implementation 'org.apache.dubbo:dubbo:2.7.2'
    implementation 'org.apache.dubbo:dubbo-registry-zookeeper:2.7.2'
    implementation 'org.apache.dubbo:dubbo-metadata-report-zookeeper:2.7.2'

    implementation 'org.apache.zookeeper:zookeeper:3.4.12'
    implementation 'org.apache.curator:curator-recipes:2.12.0'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

application.yml

server:
  port: 8786
spring:
  main:
    allow-bean-definition-overriding: true

dubbo:
  application:
    name: sdubbo
  protocol:
    name: dubbo
    port: 20882
  registry:
    address: zookeeper://10.9.44.133:2181
    simplified: true
  metadata-report:
    address: zookeeper://10.9.44.133:2181
  config-center:
    address: zookeeper://10.9.44.133:2181

啟動(dòng)類

@SpringBootApplication
@EnableDubbo
public class SDubboApplication {
    public static void main(String[] args) {
        SpringApplication.run(SDubboApplication.class, args);
    }
}

@DubboComponentScan

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
......
}

小擴(kuò)展

在 Spring 中,通過 @Import 導(dǎo)入一個(gè)外部類有三種方式

  1. 直接導(dǎo)入;
@Configuration
@Import(ExternalBean.class)
public class TestImportConfiguration {
}
  1. 導(dǎo)入一個(gè) ImportSelector 接口的實(shí)現(xiàn)類,然后重寫 selectImports 方法,在該方法中返回要導(dǎo)入類的全類名;
@Configuration
@Import(TestImportSelect.class)
public class TestImportSelectConfiguration {
}

public class TestImportSelect implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.sxy.spring.register.ExternalBean"};
    }
}
  1. 導(dǎo)入一個(gè) ImportBeanDefinitionRegistrar 接口的實(shí)現(xiàn)類,然后重寫 registerBeanDefinitions 方法,在該方法中通過 BeanDefinitionRegistry 注冊(cè) BeanDefinition;
@Configuration
@Import(TestImportBeanDefinitionRegistrar.class)
public class TestImportBeanDefinitionRegistrarCongiguration {
}

public class TestImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 注冊(cè)一個(gè)bean, 指定bean name
        registry.registerBeanDefinition("externalBean", new RootBeanDefinition(ExternalBean.class));
    }
}

DubboComponentScanRegistrar

DubboComponentScanRegistrar 實(shí)現(xiàn)了 ImportBeanDefinitionRegistrar 接口,而在它重寫的 registerBeanDefinitions 方法中做了兩件事:

  1. 注冊(cè) ServiceAnnotationBeanPostProcessor;
  2. 注冊(cè) ReferenceAnnotationBeanPostProcessor;

ServiceAnnotationBeanPostProcessor 實(shí)現(xiàn)了 BeanDefinitionRegistryPostProcessor 接口;ReferenceAnnotationBeanPostProcessor 實(shí)現(xiàn)了 InstantiationAwareBeanPostProcessorAdapter 接口。 了解Spring的同學(xué)都知道這是Spring的擴(kuò)展接口。

小擴(kuò)展

  1. BeanFactoryPostProcessor:在實(shí)例化bean之前,可以修改BeanDefinition信息;
  2. BeanDefinitionRegistryPostProcessor: BeanFactoryPostProcessor 接口的子類,在BeanFactoryPostProcessor之前執(zhí)行,可用于創(chuàng)建 BeanDefinition;
  3. BeanPostProcessor: Bean初始化前后執(zhí)行。
  4. InstantiationAwareBeanPostProcessor:BeanPostProcessor 的子類,實(shí)例化前后執(zhí)行;
  5. ApplicationContextAwareProcessor:實(shí)現(xiàn)了BeanPostProcessor,在postProcessBeforeInitialization中注入各種Aware接口;
ServiceAnnotationBeanPostProcessor

以一個(gè)dubbo provider為例

@org.apache.dubbo.config.annotation.Service
public class LeannImpl implements ILearn {
    @Override
    public String learn(String name) {
        return "學(xué)習(xí): " + name;
    }
}

ServiceAnnotationBeanPostProcessor#postProcessBeanDefinitionRegistry 的方法中,主要做了兩件事:

  1. 根據(jù)配置的包掃描路徑找到所有帶有 @org.apache.dubbo.config.annotation.Service 注解的類,為這些類創(chuàng)建 BeanDefinition ,然后注冊(cè)到IOC容器中;這部分實(shí)現(xiàn)隱藏在 DubboClassPathBeanDefinitionScanner#scan 方法中。
  2. 為每個(gè)原始類再創(chuàng)建一個(gè) ServiceBean 類型的 BeanDefinition 信息。

即:每一個(gè)dubbo服務(wù)最終會(huì)在IOC容器中對(duì)應(yīng)兩個(gè)Bean,一個(gè)是原始類型,一個(gè)是 ServiceBean 類型, ServiceBean 其實(shí)是一個(gè) FactoryBean , 是實(shí)現(xiàn)服務(wù)暴露的關(guān)鍵,這里不展開。
以上面的例子為例,最終兩個(gè)Bean對(duì)應(yīng)的BeanName分別為:leannImplServiceBean:com.sxy.sdubbo.service.ILearn

ReferenceAnnotationBeanPostProcessor

以一個(gè)dubbo consumer為例

@Component("demoServiceComponent")
public class DemoServiceComponent implements DemoService {
    @Reference(timeout = 3000)
    private DemoService demoService;

    @Override
    public String sayHello(String name) {
        return demoService.sayHello(name);
    }
}

ReferenceAnnotationBeanPostProcessor 主要做了兩件事:

  1. 創(chuàng)建一個(gè)代理服務(wù);
  2. DemoServiceComponent 注入值,即 DemoServiceComponent.demoService = 代理服務(wù);

即: DemoServiceComponent 僅僅代表 Spring 容器中的一個(gè)普通Bean;而 @Reference注解標(biāo)注demoService屬性 最終指向的是動(dòng)態(tài)創(chuàng)建的一個(gè)代理服務(wù),就是通過這個(gè)代理服務(wù)實(shí)現(xiàn)與provider通信。

至此,注解模式下,dubbo服務(wù)注冊(cè)與引用流程已經(jīng)很清晰了,具體的實(shí)現(xiàn)細(xì)節(jié)可以查看源碼。

自動(dòng)化配置

自動(dòng)化配置其實(shí)是springboot提供的一個(gè)特性,其目的就是盡量讓用戶原理各種繁瑣配置, 其核心原理就是讀取 META-INF/spring.factories 中的自動(dòng)化配置類,下面簡(jiǎn)單介紹一下。

Spring的自動(dòng)化配置

啟動(dòng)springboot應(yīng)用的時(shí)候會(huì)添加一個(gè) @SpringBootApplication 注解,而該注解中包含了 @EnableAutoConfiguration 注解,而 @EnableAutoConfiguration 就是實(shí)現(xiàn)自動(dòng)化配置的關(guān)鍵

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
......
}

核心就在 AutoConfigurationImportSelector 類,它實(shí)現(xiàn)了 ImportSelector 接口,其實(shí)主要就做了一件事情:

  1. 通過 SpringFactoriesLoader#loadFactories 方法加載 classpath 下所有 JAR 文件的 META-INF/spring.factories 文件,然后提取出文件中的所有 xxxEnableAutoConfiguration,這樣就相當(dāng)于將所有的 xxxEnableAutoConfiguration 注冊(cè)到 Spring 容器中了。當(dāng)然,這些 xxxEnableAutoConfiguration 一般會(huì)結(jié)合各種 @Conditional 來判斷是否創(chuàng)建Bean。

dubbo-spring-boot-starter

springboot 項(xiàng)目就是由一個(gè)個(gè) starter 組成的,一個(gè) starter 通常包含了該模塊需要的依賴,通常自動(dòng)化配置也是在 starter 中完成的。

dubbo在springboot應(yīng)用中的自動(dòng)化配置也是通過一個(gè) starter 來完成了,官方Git地址:dubbo-spring-boot-project

那么,在自動(dòng)化配置模式先,dubbo與springboot整合應(yīng)該怎么做? 可以用外部化配置,也可以用注解的方式來配置,這里以注解的方式配置為例:

依賴

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    
    // 因?yàn)槟壳?2019/07/19)dubbo-spring-boot-starter最新只有2.7.1版本
    implementation 'org.apache.dubbo:dubbo-spring-boot-starter:2.7.1'
    implementation 'org.apache.dubbo:dubbo:2.7.2'
    implementation 'org.apache.dubbo:dubbo-registry-zookeeper:2.7.2'
    implementation 'org.apache.dubbo:dubbo-metadata-report-zookeeper:2.7.2'

    implementation 'org.apache.zookeeper:zookeeper:3.4.12'
    implementation 'org.apache.curator:curator-recipes:2.12.0'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

啟動(dòng)類

// @EnableDubbo 不需要加這個(gè)注解
@SpringBootApplication
public class SDubboApplication {
    public static void main(String[] args) {
        SpringApplication.run(SDubboApplication.class, args);
    }

    @Configuration
    @PropertySource("classpath:/dubbo-provider.properties")
    static class ProviderConfiguration {
        @Bean
        public RegistryConfig registryConfig() {
            RegistryConfig registryConfig = new RegistryConfig();
            registryConfig.setAddress("zookeeper://10.9.44.133:2181");

            // 注冊(cè)簡(jiǎn)化版的的url到注冊(cè)中心
            registryConfig.setSimplified(true);
            return registryConfig;
        }
        @Bean
        public MetadataReportConfig metadataReportConfig() {
            MetadataReportConfig metadataReportConfig = new MetadataReportConfig();
            metadataReportConfig.setAddress("zookeeper://10.9.44.133:2181");
            return metadataReportConfig;
        }
        @Bean
        public ConfigCenterConfig configCenterConfig() {
            ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();
            configCenterConfig.setAddress("zookeeper://10.9.44.133:2181");
            return configCenterConfig;
        }
    }
}

dubbo-provider.properties

dubbo.application.name=sdubbo
dubbo.protocol.name=dubbo
dubbo.protocol.port=20882
# 多了一個(gè)包掃描,在當(dāng)前 starter 版本中,這個(gè)屬性必須配置
dubbo.scan.base-packages =com.sxy.sdubbo

與注解方式的區(qū)別:

  1. 添加 dubbo-spring-boot-starter 依賴;
  2. 不需要配置 @EnableDubbo 注解;
  3. 需要配置包掃描路徑 dubbo.scan.base-packages

其實(shí)現(xiàn)原理就是springboot中的自動(dòng)化配置:
dubbo-spring-boot-starter 的pom.xml文件中引入了 dubbo-spring-boot-autoconfigure 模塊, dubbo-spring-boot-autoconfigure 的pom.xml文件中引入了 dubbo-spring-boot-autoconfigure-compatible 模塊;

  1. dubbo-spring-boot-autoconfigure 模塊中,META-INF/spring.factories 文件內(nèi)容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBinding2AutoConfiguration
  1. dubbo-spring-boot-autoconfigure-compatible 模塊中,META-INF/spring.factories 文件內(nèi)容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration,\
org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBindingAutoConfiguration
org.springframework.context.ApplicationListener=\
org.apache.dubbo.spring.boot.context.event.OverrideDubboConfigApplicationListener,\
org.apache.dubbo.spring.boot.context.event.WelcomeLogoApplicationListener,\
org.apache.dubbo.spring.boot.context.event.AwaitingNonWebApplicationListener
org.springframework.boot.env.EnvironmentPostProcessor=\
org.apache.dubbo.spring.boot.env.DubboDefaultPropertiesEnvironmentPostProcessor
org.springframework.context.ApplicationContextInitializer=\
org.apache.dubbo.spring.boot.context.DubboApplicationContextInitializer

DubboRelaxedBindingAutoConfiguration 主要是和屬性解析有關(guān),這里不做介紹;核心還是 DubboAutoConfiguration , 在該類中有一下兩段關(guān)鍵代碼

/**
 * @ConditionalOnProperty(prefix = DUBBO_SCAN_PREFIX, name = BASE_PACKAGES_PROPERTY_NAME) 強(qiáng)制要求了我們需要配置包掃描路徑,否則該Bean不會(huì)被創(chuàng)建
 * Creates {@link ServiceAnnotationBeanPostProcessor} Bean
 *
 * @param propertyResolver {@link PropertyResolver} Bean
 * @return {@link ServiceAnnotationBeanPostProcessor}
 */
@ConditionalOnProperty(prefix = DUBBO_SCAN_PREFIX, name = BASE_PACKAGES_PROPERTY_NAME)
@ConditionalOnBean(name = BASE_PACKAGES_PROPERTY_RESOLVER_BEAN_NAME)
@Bean
public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor(
        @Qualifier(BASE_PACKAGES_PROPERTY_RESOLVER_BEAN_NAME) PropertyResolver propertyResolver) {
    Set<String> packagesToScan = propertyResolver.getProperty(BASE_PACKAGES_PROPERTY_NAME, Set.class, emptySet());
    return new ServiceAnnotationBeanPostProcessor(packagesToScan);
}

/**
 * Creates {@link ReferenceAnnotationBeanPostProcessor} Bean if Absent bean工廠不存在referenceAnnotationBeanPostProcessor時(shí)創(chuàng)建
 *
 * @return {@link ReferenceAnnotationBeanPostProcessor}
 */
@ConditionalOnMissingBean
@Bean(name = ReferenceAnnotationBeanPostProcessor.BEAN_NAME)
public ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor() {
    return new ReferenceAnnotationBeanPostProcessor();
}

其實(shí)核心就是通過自動(dòng)化的方式創(chuàng)建了 ServiceAnnotationBeanPostProcessorReferenceAnnotationBeanPostProcessor,沒有通過 @EnableDubbo 注解觸發(fā)。但是感覺這樣不太好用。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容