zoukankan      html  css  js  c++  java
  • 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

      @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);
        }
  • 相关阅读:
    spring的了解以及简单框架的搭建
    动态代理
    struts2标签(转)
    使用OGNL表达式
    struts2 ValueStack
    struts2框架xml验证
    struts2 validate手动验证
    struts2自定义拦截器
    struts2文件上传
    当findById(Integer id)变成String类型
  • 原文地址:https://www.cnblogs.com/LQBlog/p/12470179.html
Copyright © 2011-2022 走看看