Dubbo服务订阅源码解析

前言

前面那篇文章我们从源码层面解析了Dubbo的服务暴露过程,今天我们继续源码解析,Dubbo服务引用/订阅流程。

环境配置

使用的Dubbo版本为3.2.0,注册中心使用zookeeper,demo为官方springboot演示代码。

Consume启动

可以看到,启动类上还是一个@EnableDubbo注解,和Provide启动并无差别,使用@DubboReference注解注入了DemoService,这个注解是不是很陌生,我们之前学习spring框架的时候只用过@Autowired、@Resource,@EnableDubbo在这里的作用和原理是什么呢?我们继续往下看

java 复制代码
public class DubboSpringInitializer {
    public static void initialize(BeanDefinitionRegistry registry) {
        //.......省略非核心代码
        // init dubbo context
        initContext(context, registry, beanFactory);
    }
    private static void initContext(DubboSpringInitContext context, BeanDefinitionRegistry registry,
                                ConfigurableListableBeanFactory beanFactory) {
        // register common beans
        DubboBeanUtils.registerCommonBeans(registry);
    }
    static void registerCommonBeans(BeanDefinitionRegistry registry) {
        ......
        //这里主要是处理@DubboReference和@Reference注解
        registerInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME,
            ReferenceAnnotationBeanPostProcessor.class);
        // register ApplicationListeners 注册监听器,这里很重要
        registerInfrastructureBean(registry, DubboDeployApplicationListener.class.getName(), DubboDeployApplicationListener.class);
        registerInfrastructureBean(registry, DubboConfigApplicationListener.class.getName(), DubboConfigApplicationListener.class);
        // Dubbo config initializer 加载配置
        registerInfrastructureBean(registry, DubboConfigBeanInitializer.BEAN_NAME, DubboConfigBeanInitializer.class);
        ......
      }

还记得上篇文章registerCommonBeans()方法里注册了一个ReferenceAnnotationBeanPostProcessor处理器不,我们debug进去源码。

可以看到@DubboReference注解的职责就是将DemoService组装成BeanDefinition注册到了BeanDefinitionMap中,这个BeanDefinition的类型是ReferenceBean,这是个什么意思呢?我们找到这个接口。

java 复制代码
public class ReferenceBean<T> implements FactoryBean<T>,
        ApplicationContextAware, BeanClassLoaderAware, BeanNameAware, InitializingBean, DisposableBean {

可以看到,它其实是一个FactoryBean,这里又牵扯到spring的知识了,我们找到ReferenceBean的getObject方法

java 复制代码
@Override
public T getObject() {
    //这里进行了重写
    if (lazyProxy == null) {
        createLazyProxy();
    }
    return (T) lazyProxy;
}
java 复制代码
private void createLazyProxy() {
    //set proxy interfaces
    //see also: org.apache.dubbo.rpc.proxy.AbstractProxyFactory.getProxy(org.apache.dubbo.rpc.Invoker<T>, boolean)
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.setTargetSource(new DubboReferenceLazyInitTargetSource());
    proxyFactory.addInterface(interfaceClass);
    Class<?>[] internalInterfaces = AbstractProxyFactory.getInternalInterfaces();
    for (Class<?> anInterface : internalInterfaces) {
        proxyFactory.addInterface(anInterface);
    }
    if (!StringUtils.isEquals(interfaceClass.getName(), interfaceName)) {
        //add service interface
        try {
            Class<?> serviceInterface = ClassUtils.forName(interfaceName, beanClassLoader);
            proxyFactory.addInterface(serviceInterface);
        } catch (ClassNotFoundException e) {
            // generic call maybe without service interface class locally
        }
    }
    //动态代理
    this.lazyProxy = proxyFactory.getProxy(this.beanClassLoader);
}

这里我们又见到了动态代理。

服务订阅

还记得在上篇文章中提到的DubboDeployApplicationListener监听器不,我们继续往下看

直接定位到init方法

java 复制代码
protected synchronized void init() {
        //创建代理
        ref = createProxy(referenceParameters);
}
private void createInvoker() {
    if (urls.size() == 1) {
        URL curUrl = urls.get(0);
        //这里
        invoker = protocolSPI.refer(interfaceClass, curUrl);
        // registry url, mesh-enable and unloadClusterRelated is true, not need Cluster.
        if (!UrlUtils.isRegistry(curUrl) &&
                !curUrl.getParameter(UNLOAD_CLUSTER_RELATED, false)) {
            List<Invoker<?>> invokers = new ArrayList<>();
            invokers.add(invoker);
            invoker = Cluster.getCluster(getScopeModel(), Cluster.DEFAULT).join(new StaticDirectory(curUrl, invokers), true);
        }
    }

中间链路比较长,我们直接跳到这里

至此,我们已经初始化好了服务代理类,后续的方法调用,就是使用的这个代理类处理器。

总结

最后,还是用一段话总结一下,ReferenceAnnotationBeanPostProcessor处理器会将带有@DubboReference注解的属性扫描成ReferenceBean类型的BeanDefinition,ReferenceBean是一个工厂bean,它的getObject方法会创建代理类。DubboDeployApplicationListener监听器接收到spring刷新完成事件后会进行服务的订阅,与注册中心建立连接,将消费方的信息进行注册,订阅服务方的信息,并写入本地临时文件,最后会创建代理类 InvokerInvocationHandler,后续远程方法的调用都是这个Handler进行处理。

相关推荐
va学弟2 分钟前
Agent入门开发(2):个性化功能添加
java·服务器·ai
8486981192 分钟前
Cursor 用 Java + Vue3 做了一个可落地的酒店管理系统(HMS),支持多门店、RBAC、财务结算,源码开源!
java·开发语言·开源
神奇小汤圆8 分钟前
JAVA 面经汇总2026最新版,1100+ 大厂面试题附答案详解
后端
程序员老邢13 分钟前
【技术底稿 23】Ollama + Docker + Ubuntu 部署踩坑实录:网络通了,参数还在调
java·经验分享·后端·ubuntu·docker·容器·milvus
:12116 分钟前
java数组2
java·算法·排序算法
酉鬼女又兒22 分钟前
JavaLeetCode 第一题「两数之和」:从暴力枚举到一遍哈希表的正确与错误实现,详解HashMap核心知识点及常见陷阱
java·开发语言·数据结构·算法·leetcode·职场和发展·散列表
JackSparrow41423 分钟前
彻底理解Java NIO(一)C语言实现 单进程+多进程+多线程 阻塞式I/O 服务器详解
java·linux·c语言·网络·后端·tcp/ip·nio
小江的记录本25 分钟前
【微服务与云原生架构】Serverless架构、FaaS/BaaS、核心原理、优缺点
java·后端·微服务·云原生·架构·系统架构·serverless
谢谢 啊sir27 分钟前
L2-060 大语言模型的推理 - java
java·人工智能·语言模型
神奇小汤圆30 分钟前
阿里云社招一面:数据库中有 1000 万数据的时候怎么分页查询?
后端