Soul API網(wǎng)關(guān)源碼解析03

目標

  • 基于apache-dubbo消息轉(zhuǎn)發(fā)

    • zookeeper 本地注冊中心搭建

    • soul admin 本地配置dubbo插件

    • 啟動soul-example-apache-dubbo-service

      • dubbo注冊服務(wù)到admin
    • 分別演示允許轉(zhuǎn)發(fā)與過濾轉(zhuǎn)發(fā)

  • 分析example-dubbo啟動完成接口的注冊

    • soul-spring-boot-starter-client-apache-dubbo注入
    • ApacheDubboServiceBeanPostProcessor
    • onApplicationEvent
  • 總結(jié)

基于apache-dubbo消息轉(zhuǎn)發(fā)

由于soul的dubbo采用zookeeper作為注冊中心,所以下面我們就先搭建zookeeper.

zookeeper本地注冊中心搭建

  • 下載zookeeper(zk)安裝包

zookeeper

  • 解壓zookeeper安裝包
tar -xvf apache-zookeeper-3.6.2-bin.tar.gz -C /opt
vim conf/zoo.cfg # 修改配置文件

 # The number of milliseconds of each tick
    2 tickTime=2000
    3 # The number of ticks that the initial
    4 # synchronization phase can take
    5 initLimit=10
    6 # The number of ticks that can pass between
    7 # sending a request and getting an acknowledgement
    8 syncLimit=5
    9 # the directory where the snapshot is stored.
   10 # do not use /tmp for storage, /tmp here is just
   11 # example sakes.
   12 dataDir=/Volumes/Nuo/tools/data/zookeeper
   13 dataLogDir=/Volumes/Nuo/tools/data/zookeeper/logs
   14 # the port at which the clients will connect
   15 clientPort=2181</pre>
  • 啟動zk服務(wù)
zkServer.sh start

/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /Volumes/Nuo/tools/apache-zookeeper-3.6.2-bin/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
# 表示 zk 啟動成功

soul admin啟動配置dubbo

register: 填寫我們剛啟動的zk服務(wù)地址: zookeeper://localhost:2181

狀態(tài): 打開

啟動soul-example-apache-dubbo-service

  • 注冊服務(wù)到admin
image
@Configuration
public class SoulApacheDubboClientConfiguration {

    /**
     * Apache dubbo service bean post processor alibaba dubbo service bean post processor.
     *
     * @param dubboConfig the dubbo config
     * @return the alibaba dubbo service bean post processor
     */
    @Bean
    public ApacheDubboServiceBeanPostProcessor apacheDubboServiceBeanPostProcessor(final DubboConfig dubboConfig) {
        return new ApacheDubboServiceBeanPostProcessor(dubboConfig);
    }

    /**
     * Dubbo config dubbo config.
     *
     * @return the dubbo config
     */
    @Bean
    @ConfigurationProperties(prefix = "soul.dubbo")
    public DubboConfig dubboConfig() {
        return new DubboConfig();
    }
}

dubbo服務(wù)注冊admin運行方式與sprinigmvc類似。根據(jù)配置的admin地址和自動化注入Bean方式進行接口注入

public void onApplicationEvent(final ContextRefreshedEvent contextRefreshedEvent) {
    if (Objects.nonNull(contextRefreshedEvent.getApplicationContext().getParent())) {
        return;
    }
    // Fix bug(https://github.com/dromara/soul/issues/415), upload dubbo metadata on ContextRefreshedEvent
    Map<String, ServiceBean> serviceBean = contextRefreshedEvent.getApplicationContext().getBeansOfType(ServiceBean.class);
    for (Map.Entry<String, ServiceBean> entry : serviceBean.entrySet()) {
        executorService.execute(() -> handler(entry.getValue()));
    }

使用反射獲取需要代理的接口,首先根據(jù)@Servic獲取類,然后根據(jù)類獲取對應(yīng)接口的名稱

image

然后將獲取到的名稱同步到admin,下圖就是自動獲取配置并且沾水

image

演示dubbo轉(zhuǎn)發(fā)

image
image

分析example-dubbo啟動完成接口的注冊

soul-spring-boot-starter-client-apache-dubbo注入ApacheDubboServiceBeanPostProcessor初始化

自定義boot starter會自動注入

public ApacheDubboServiceBeanPostProcessor(final DubboConfig dubboConfig) {
    String contextPath = dubboConfig.getContextPath();
    String adminUrl = dubboConfig.getAdminUrl();
    if (StringUtils.isEmpty(contextPath)
            || StringUtils.isEmpty(adminUrl)) {
        throw new RuntimeException("apache dubbo client must config the contextPath, adminUrl");
    }
    this.dubboConfig = dubboConfig;
    // 拼接發(fā)送注冊地址的url (admin 接口地址)
    url = dubboConfig.getAdminUrl() + "/soul-client/dubbo-register";
    executorService = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
}

ApplicationListene<ContextRefreshedEvent>

ContextRefreshedEvent:容器刷新完成(所有bean都完全創(chuàng)建)會發(fā)布這個事件

public class ApacheDubboServiceBeanPostProcessor implements ApplicationListener<ContextRefreshedEvent>

dubbo 客戶端初始化與divide 初始化缺少一個Bean后置處理,原因是Dubbo 依賴注冊中心,要將所有的接口類都注冊到注冊中心之后,我們在發(fā)起注冊。而ApplicationListener觸發(fā)是發(fā)生在IOC容器初始化完成Bean后置處理之后。

onApplicationEvent

@Override
public void onApplicationEvent(final ContextRefreshedEvent contextRefreshedEvent) {
    if (Objects.nonNull(contextRefreshedEvent.getApplicationContext().getParent())) {
        return;
    }
    // Fix bug(https://github.com/dromara/soul/issues/415), upload dubbo metadata on ContextRefreshedEvent
    Map<String, ServiceBean> serviceBean = contextRefreshedEvent.getApplicationContext().getBeansOfType(ServiceBean.class);
    for (Map.Entry<String, ServiceBean> entry : serviceBean.entrySet()) {
        executorService.execute(() -> handler(entry.getValue()));
    }
}

通過@ImportResource裝備dubbo的兩個service

@ImportResource({"classpath:spring-dubbo.xml"})
public class TestApacheDubboApplication {
    /**
     * Main Entrance.
     *
     * @param args startup arguments
     */
    public static void main(final String[] args) {
        SpringApplication.run(TestApacheDubboApplication.class, args);
    }
}

<dubbo:service timeout="10000" interface="org.dromara.soul.examples.dubbo.api.service.DubboTestService" ref="dubboTestService"/>
<dubbo:service timeout="10000" interface="org.dromara.soul.examples.dubbo.api.service.DubboMultiParamService" ref="dubboMultiParamService"/>

接口注冊到admin

private void handler(final ServiceBean serviceBean) {
    Class<?> clazz = serviceBean.getRef().getClass();
    if (ClassUtils.isCglibProxyClass(clazz)) {
        String superClassName = clazz.getGenericSuperclass().getTypeName();
        try {
            clazz = Class.forName(superClassName);
        } catch (ClassNotFoundException e) {
            log.error(String.format("class not found: %s", superClassName));
            return;
        }
    }
    final Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(clazz);
    for (Method method : methods) {
        SoulDubboClient soulDubboClient = method.getAnnotation(SoulDubboClient.class);
        if (Objects.nonNull(soulDubboClient)) {
            RegisterUtils.doRegister(buildJsonParams(serviceBean, soulDubboClient, method), url, RpcTypeEnum.DUBBO);
        }
    }
}

使用反射拿到接口參數(shù),注冊到admin

參考

soul github
soul document

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容