dubbo源码阅读-服务暴露(七)之本地暴露(Injvm)

什么是本地暴露

具体可以参考:https://zhuanlan.zhihu.com/p/98423741

我们从上一篇的服务暴露本地暴露开始看起

https://www.cnblogs.com/LQBlog/p/12469007.html#autoid-6-13-0

com.alibaba.dubbo.config.ServiceConfig#exportLocal

    @SuppressWarnings({"unchecked", "rawtypes"})
    private void exportLocal(URL url) {
        //如果协议为不是injvm
        if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
            //生成本地Url
            URL local = URL.valueOf(url.toFullString())
                    .setProtocol(Constants.LOCAL_PROTOCOL)//injvm 注意这里把协议强制设置成了injvm
                    .setHost(LOCALHOST) //127.0.0.1
                    .setPort(0);
            //service.classimpl 将本地暴露接口存入StaticContext map key为接口 value为实现类的名字
            StaticContext.getContext(Constants.SERVICE_IMPL_CLASS).put(url.getServiceKey(), getServiceClass(ref));
            /**
             * <1>使用 ProxyFactory 创建 Invoker 对象 根据url配置的proxy来作为spi的Key 缺省值是javasist 动态生成一个代理class 也可以使用jdk
             * private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
             * 使用 Protocol 暴露 Invoker 对象 根据url的protcol 来作为SPIKey查找 缺省值duboo
             *
             * private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
             */

            Exporter<?> exporter = protocol.export(
                    proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
            // 添加到 `exporters`
            exporters.add(exporter);
            logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
        }
    }

 

类图

 

 

为什么会调用ProtocolListenerWrapper

按照https://www.cnblogs.com/LQBlog/p/12453900.html 理解 那么这里的protocol应该是InjvmProtocol

我们回到:https://www.cnblogs.com/LQBlog/p/12453900.html#autoid-8-11-0   注释处://当前类是否含有构造函数 并且为当前SPI接口 装饰者 具体可以参考

再回到:https://www.cnblogs.com/LQBlog/p/12453900.html#autoid-11-1-0 可可以发现动态代理都是调用的getExtention(name)方法

再看:https://www.cnblogs.com/LQBlog/p/12453900.html#autoid-4-3-0 18->19

//逐级生成代理对象返回
            if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }

可以发现这里会对SPI配置的含有构造函数参数为SPI接口类型的 生成逐级代理

ProtocolFilterWrapper,QosProtocolWrapper,ProtocolListenerWrapper 这几个接口都是SPI代理接口 所以返回的这3个对象的代理对象

ProtocolFilterWrapper

<1>export

com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper#export

    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        //registry 如果是registry 直接调用 代理抵消的export传入invoker invoke封装了代理ServiceImpl信息 以及registryUrl?export=暴露url信息
        if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
            return protocol.export(invoker);
        }
        // <2>调用buildInvokerChain 传入service.filter provider,<3>调用被代理对象的export
        //buildInvokerChain 后就是返回的代理对象的Invoker
        return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
    }

<2>buildInvokerChain

com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper#export

->

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;
        //获取激活对象 参数如:key service.filter gruop=provider
        //getActivateExtension内部实现可以看:https://www.cnblogs.com/LQBlog/p/12453900.html#autoid-6-0-0
        List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
        if (!filters.isEmpty()) {
            //循环生成invoker调用链条
            for (int i = filters.size() - 1; i >= 0; i--) {
                //逐级dialing
                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() {
                        //调用被代理对象的url
                        return invoker.getUrl();
                    }

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

                    @Override
                    public Result invoke(Invocation invocation) throws RpcException {
                        //代理
                        return filter.invoke(next, invocation);
                    }

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

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

QosProtocolWrapper

<3>export

QOS使用:https://www.jianshu.com/p/e117b580b996,https://segmentfault.com/a/1190000041003358

  @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        //如果协议是registry 则开启qos
        if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
            //开启qos模块 具体可看http://dubbo.apache.org/zh-cn/docs/user/references/qos.html
            startQosServer(invoker.getUrl());
            return protocol.export(invoker);
        }
        //<4>ProtocolListenerWrapper
        return protocol.export(invoker);
    }

ProtocolListenerWrapper

<4>export

    /**
     * 用于给 Exporter 增加 ExporterListener ,监听 Exporter 暴露完成和取消暴露完成。
     * @param invoker Service invoker
     * @param <T>
     * @return
     * @throws RpcException
     */
    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
            return protocol.export(invoker);
        }
        //<5>InjvmProtocol
        Exporter<T> exporter=protocol.export(invoker);

        // SPI扩展点 返回监听器 Collections.unmodifiableList 返回的集合不可修改
        List<ExporterListener> exporterListenerList=Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
                .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY));
        //https://www.cnblogs.com/killbug/p/7341968.html 返回一个带监听功能的代理类
        //代理类 在unexport和exported 会调用监听器的unexported,exported方法和 并传入invoker
        return new ListenerExporterWrapper<T>(exporter,
                exporterListenerList);
    }

 

InjvmProtocol

<5>export

com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol#export

 @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        //创建一个InjvmExporter代理对象 内部保存了invoker以及所有的本地发布实例 key为 service com.alibaba.dubbo.demo.DemoService
        //<6>exporterMap为InJvmProtocol成员变量 构造函数内部会add key为Service全名称
        return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
    }

InjvmExporter

<6>exporter构造函数

    InjvmExporter(Invoker<T> invoker, String key, Map<String, Exporter<?>> exporterMap) {
        super(invoker);
        //key为service全名称
        this.key = key;
        //为协议成员变量的map
        this.exporterMap = exporterMap;
        //将当前export添加到map
        exporterMap.put(key, this);
    }

 

posted @ 2020-03-12 16:37  意犹未尽  阅读(712)  评论(0编辑  收藏  举报