dubbo源码解析之服务export 本地服务

本文详细解析了Dubbo服务export本地服务的过程,从ServiceConfig#exportLocal开始,深入到ProtocolFilterWrapper构建filter链,探讨了filter的扩展性和ExporterListener的实现。接着讲解了InjvmProtocol#export的细节,包括如何获取serviceKey和服务export后的对象。此外,还提及了scope配置为非injvm时的服务export流程。整个解析旨在理解Dubbo服务暴露的内部机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说在前面
前期回顾

sharding-jdbc源码解析 更新完毕

spring源码解析 更新完毕

spring-mvc源码解析 更新完毕

spring-tx源码解析 更新完毕

spring-boot源码解析 更新完毕

rocketmq源码解析 更新完毕

dubbo源码解析 更新中

sharding-sphere源码解析 计划中

netty源码解析 计划中

spring-cloud-alibaba-dubbo源码解析 计划中

github https://github.com/tianheframe

sharding-jdbc源码解析 更新完毕

rocketmq 更新完毕

dubbo源码解析 更新中

seata源码解析 更新中

spring-cloud-tianhe 更新中

mq-tianhe 计划中

rpc-tianhe 计划中
更多源码解析请关注天河聊架构微信公众号

源码解析
https://github.com/tianheframe/dubbo.git dubbo源码解析后的源码和公号文章同步更新。

进入这个方法,com.alibaba.dubbo.config.ServiceConfig#exportLocal

private void exportLocal(URL url) {
//        injvm协议
        if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
            URL local = URL.valueOf(url.toFullString())
                    .setProtocol(Constants.LOCAL_PROTOCOL)
//                    127.0.0.1 本地host
                    .setHost(LOCALHOST)
                    .setPort(0);
            ServiceClassHolder.getInstance().pushServiceClass(getServiceClass(ref));
//            服务注册=》
            Exporter<?> exporter = protocol.export(
                    proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
            exporters.add(exporter);
            logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
        }
    }

如果scope属性指定了injvm会走export 服务 本地服务,调用这个方法proxyFactory.getInvoker会生成一个invoker的代理类,会进入到这个方法com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper#export

@Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
//          ProtocolListenerWrapper.export()
            return protocol.export(invoker);
        }
        return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
    }

进入到这个方法构建filter过滤器链,com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper#buildInvokerChain

private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
        Invoker<T> last = invoker;
//        过滤器链是list实现,用spi加载filter chain
        List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
        if (!filters.isEmpty()) {
            for (int i = filters.size() - 1; i >= 0; i--) {
                final Filter filter = filters.get(i);
                final Invoker<T> next = last;
                last = new Invoker<T>() {

                    @Override
                    public Class<T> getInterface() {
                        return invoker.getInterface();
                    }

                    @Override
                    public URL getUrl() {
                        return invoker.getUrl();
                    }

                    @Override
                    public boolean isAvailable() {
                        return invoker.isAvailable();
                    }

                    @Override
                    public Result invoke(Invocation invocation) throws RpcException {
//                        ConsumerContextFilter.invoke()    com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke()   com.alibaba.dubbo.monitor.support.MonitorFilter.invoke()
                        return filter.invoke(next, invocation);
                    }

                    @Override
                    public void destroy() {
                        invoker.destroy();
                    }

                    @Override
                    public String toString() {
                        return invoker.toString();
                    }
                };
            }
        }
        return last;
    }

filter链数据结构是用list实现,用spi机制来实现filter chain的扩展性,dubbo默认实现了限流相关等很多过滤器链,自己也可以实现自己的filter chain实现进行扩展,比如在dubbo调用过程中处理自己的个性化的业务逻辑,这里是一个扩展点

private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
        Invoker<T> last = invoker;
//        过滤器链是list实现,用spi加载filter chain
        List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
        if (!filters.isEmpty()) {
            for (int i = filters.size() - 1; i >= 0; i--) {
                final Filter filter = filters.get(i);
                final Invoker<T> next = last;
                last = new Invoker<T>() {

                    @Override
                    public Class<T> getInterface() {
                        return invoker.getInterface();
                    }

                    @Override
                    public URL getUrl() {
                        return invoker.getUrl();
                    }

                    @Override
                    public boolean isAvailable() {
                        return invoker.isAvailable();
                    }

                    @Override
                    public Result invoke(Invocation invocation) throws RpcException {
//                        ConsumerContextFilter.invoke()    com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke()   com.alibaba.dubbo.monitor.support.MonitorFilter.invoke()
                        return filter.invoke(next, invocation);
                    }

                    @Override
                    public void destroy() {
                        invoker.destroy();
                    }

                    @Override
                    public String toString() {
                        return invoker.toString();
                    }
                };
            }
        }
        return last;
    }

接下来会进入到这个方法,com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper#export

@Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
//          RegistryProtocol.export()
            return protocol.export(invoker);
        }
        return new ListenerExporterWrapper<T>(protocol.export(invoker),
                Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
                        .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
    }

com.alibaba.dubbo.rpc.ExporterListener 这里也可以实现这个接口在服务export、unexport的时候实现自己的监听器,有一个默认实现com.alibaba.dubbo.rpc.listener.ExporterListenerAdapter,如果自己需要扩展可以覆盖这个适配器类或者实现这个接口实现自己的业务逻辑


@SPI
public interface ExporterListener {

    /**
     * The exporter exported.
     *
     * @param exporter
     * @throws RpcException
     * @see com.alibaba.dubbo.rpc.Protocol#export(Invoker)
     */
    void exported(Exporter<?> exporter) throws RpcException;

    /**
     * The exporter unexported.
     *
     * @param exporter
     * @throws RpcException
     * @see com.alibaba.dubbo.rpc.Exporter#unexport()
     */
    void unexported(Exporter<?> exporter);
public abstract class ExporterListenerAdapter implements ExporterListener {

    @Override
    public void exported(Exporter<?> exporter) throws RpcException {
    }

    @Override
    public void unexported(Exporter<?> exporter) throws RpcException {
    }

}

接下来会进入到这个方法,com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol#export

@Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
//        serviceKey=group+interface+version
        return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
    }

进入这个方法,com.alibaba.dubbo.common.URL#getServiceKey 服务的serviceKey是用group、服务接口名、version进行标识服务唯一的,服务export完毕会返回一个com.alibaba.dubbo.rpc.protocol.injvm.InjvmExporter对象,最后会返回一个com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper对象

如果scope的配置不是injvm会从远程进行服务export,下篇会介绍从远程export

说在最后
本次解析仅代表个人观点,仅供参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值