• 7.2 服务本地暴露


    为了安全:服务启动的ip全部使用10.10.10.10

    服务暴露的流程其实就是下边这样(图片来自:http://www.iteye.com/topic/1123039

    简单看一下服务暴露的伪代码:

     1 /**
     2  * dubbo 服务暴露伪代码
     3  */
     4 public class DubboProviderSimpleCode {
     5     private final List<Exporter<?>> exporters = new ArrayList<Exporter<?>>();
     6     /**
     7      * 获取注册中心url列表
     8      * [ registry://10.211.55.5:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&client=curator&dubbo=2.0.0&pid=2956&registry=zookeeper&timestamp=1507004600231 ]
     9      */
    10     List<URL> registryURLs = loadRegistries();//获取注册中心url列表
    11     for (ProtocolConfig protocolConfig : protocols) {
    12         /**
    13          * 创建协议url
    14          * dubbo://10.10.10.10:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=2956&side=provider&timestamp=1507004625957
    15          */
    16         URL url = new URL(name, host, port, path, map);
    17         /**
    18          * 本地暴露
    19          */
    20         if (<dubbo:service scope!=remote>) {
    21             /**
    22              * 构造injvm协议的url
    23              * injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=2956&side=provider&timestamp=1507004625957
    24              */
    25             URL local = URL.valueOf(url.toFullString())
    26                     .setProtocol(Constants.LOCAL_PROTOCOL)
    27                     .setHost(NetUtils.LOCALHOST)
    28                     .setPort(0);
    29             Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, local);
    30             Exporter<?> exporter = protocol.export(invoker);
    31             exporters.add(exporter);
    32         }
    33         /**
    34          * 远程暴露
    35          */
    36         if (<dubbo:service scope!=local>) {
    37             for (URL registryURL : registryURLs) {
    38                 Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
    39                 Exporter<?> exporter = protocol.export(invoker);
    40                 exporters.add(exporter);
    41             }
    42         }
    43     }
    44 }

    本地暴露:

    • 通过JavassistProxyFactory(默认)将具体的实现类包装成AbstractProxyInvoker实例
    • InjvmProtocol将上述的AbstractProxyInvoker实例转换成Exporter

    远程暴露:

    • 通过JavassistProxyFactory(默认)将具体的实现类包装成AbstractProxyInvoker实例
    • DubboProtocol将上述的AbstractProxyInvoker实例转换成Exporter

     本节来看本地暴露。首先给出整个本地服务暴露的调用链

     1 ServiceBean.onApplicationEvent(ApplicationEvent event)
     2 -->ServiceConfig.export()
     3    -->doExport()
     4       -->doExportUrls()
     5          -->loadRegistries(boolean provider) //
     6          -->doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs)
     7             -->Wrapper getWrapper(Class<?> c)
     8                -->makeWrapper(Class<?> c)
     9             -->new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map)
    10             
    11             <!--   本地暴露   -->
    12             -->exportLocal(url)
    13                -->构造injvm协议的url:injvmUrl
    14                <!--  1 将ref包装成Invoker   -->
    15                -->ProxyFactory$Adaptive.getInvoker(ref实例, interfaceClass, injvmUrl)
    16                   -->ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension("javassist")
    17                   -->StubProxyFactoryWrapper.getInvoker(T proxy, Class<T> type, URL url)
    18                      -->JavassistProxyFactory.getInvoker(T proxy, Class<T> type, URL url)
    19                         -->Wrapper getWrapper(Class<?> c)
    20                            -->makeWrapper(Class<?> c)
    21                         -->new AbstractProxyInvoker<T>(ref实例, interfaceClass, injvmUrl)
    22                <!--  2 将Invoker暴露为Exporter   -->
    23                -->Protocol$Adaptive.export(Invoker<T> invoker)
    24                   -->ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension("injvm")
    25                   -->ProtocolListenerWrapper.export(Invoker<T> invoker)
    26                      -->ProtocolFilterWrapper.export(Invoker<T> invoker)
    27                         -->buildInvokerChain(final Invoker<T> invoker, key:"service.filter", group:"provider")
    28                            -->ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(injvmUrl, "service.filter", "provider")
    29                         -->InjvmProtocol.export(Invoker<T> invoker)
    30                            -->new InjvmExporter(Invoker<T> invoker, key:"com.alibaba.dubbo.demo.DemoService", Map<String, Exporter<?>> exporterMap)
    31                               -->InjvmExporter.exporterMap({"com.alibaba.dubbo.demo.DemoService" -> "injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=3207&side=provider&timestamp=1507009133930"})
    32                   -->new ListenerExporterWrapper(Exporter<T> exporter, List<ExporterListener> listeners) : 使用listener包装invoker
    33                <!--  3 将Invoker暴露为Exporter   -->
    34                -->ServiceConfig#exporters.add(exporter) 

    本地暴露的代码如下:

     1     /**
     2      * 本地暴露
     3      * 1 根据传进来的url(例如dubbo协议的url)构造injvm协议的url
     4      * injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=2999&side=provider&timestamp=1507005507343
     5      *
     6      * 2 将ref包装为AbstractProxyInvoker实例
     7      * 3 将AbstractProxyInvoker实例转换为InjvmExporter
     8      *
     9      * @param url dubbo://10.10.10.10:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=2999&side=provider&timestamp=1507005507343
    10      */
    11     @SuppressWarnings({"unchecked", "rawtypes"})
    12     private void exportLocal(URL url) {
    13         if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
    14             URL local = URL.valueOf(url.toFullString()).setProtocol(Constants.LOCAL_PROTOCOL).setHost(NetUtils.LOCALHOST).setPort(0);
    15             Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, local);
    16             Exporter<?> exporter = protocol.export(invoker);
    17             exporters.add(exporter);
    18             logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
    19         }
    20     }

    为了清晰,这里对exportLocal(URL url)做了稍稍的改动。整体流程如下:

    1 首先将dubbo协议的url,改成了injvm协议的url:local;

    2 将具体服务类ref通过proxyFactory包装成AbstractProxyInvoker实例;

    3 将AbstractProxyInvoker实例转化为Exporter实例;

    4 最后将生成的Exporter实例存放在ServiceConfig的List<Exporter> exporters中。

    一 具体服务包装成AbstractProxyInvoker实例

    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, local);

    具体服务:com.alibaba.dubbo.demo.provider.DemoServiceImpl。调用链如下:

    1                <!--  1 将ref包装成Invoker   -->
    2                -->ProxyFactory$Adaptive.getInvoker(ref实例, interfaceClass, injvmUrl)
    3                   -->ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension("javassist")
    4                   -->StubProxyFactoryWrapper.getInvoker(T proxy, Class<T> type, URL url)
    5                      -->JavassistProxyFactory.getInvoker(T proxy, Class<T> type, URL url)
    6                         -->Wrapper getWrapper(Class<?> c)
    7                            -->makeWrapper(Class<?> c)
    8                         -->new AbstractProxyInvoker<T>(ref实例, interfaceClass, injvmUrl)

    1 ProxyFactory$Adaptive.getInvoker(java.lang.Object arg0, java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2)

     1     public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2) throws com.alibaba.dubbo.rpc.RpcException {
     2         if (arg2 == null)
     3             throw new IllegalArgumentException("url == null");
     4         com.alibaba.dubbo.common.URL url = arg2;
     5         String extName = url.getParameter("proxy", "javassist");
     6         if(extName == null)
     7             throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])");
     8         com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName);
     9         return extension.getInvoker(arg0, arg1, arg2);
    10     }
    • arg0: com.alibaba.dubbo.demo.provider.DemoServiceImpl 实例
    • arg1: interface com.alibaba.dubbo.demo.DemoService Class对象
    • arg2: injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=3275&side=provider&timestamp=1507010529605

    这里,首先是参数检查和赋值。之后获取key为javassist的ProxyFactory实现类:JavassistProxyFactory,该类会在spi进行aop的时候包裹在StubProxyFactoryWrapper中,最终调用链为:

    ProxyFactory$Adaptive -> StubProxyFactoryWrapper -> JavassistProxyFactory

    2 StubProxyFactoryWrapper.getInvoker(T proxy, Class<T> type, URL url)

    1     public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException {
    2         return proxyFactory.getInvoker(proxy, type, url);
    3     }

    这里的proxyFactory就是JavassistProxyFactory实例了。

    3 JavassistProxyFactory.getInvoker(T proxy, Class<T> type, URL url)

     1     public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
     2         // TODO Wrapper类不能正确处理带$的类名
     3         final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
     4         return new AbstractProxyInvoker<T>(proxy, type, url) {
     5             @Override
     6             protected Object doInvoke(T proxy, String methodName,
     7                                       Class<?>[] parameterTypes,
     8                                       Object[] arguments) throws Throwable {
     9                 return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
    10             }
    11         };
    12     }

    这里首先会创建一个class com.alibaba.dubbo.demo.provider.DemoServiceImpl的包装类Wrapper:Wrapper.getWrapper(Class<DemoServiceImpl>)。该类记录了DemoServiceImpl的属性名称,方法名称等信息。具体代码如下:

     1 package com.alibaba.dubbo.demo;
     2 
     3 import com.alibaba.dubbo.common.bytecode.Wrapper;
     4 import java.util.HashMap;
     5 
     6 public class Wrapper1 extends Wrapper {
     7 
     8     public static String[] pns;//property name array
     9     public static java.util.Map pts = new HashMap();//<property key, property value>
    10     public static String[] mns;//method names
    11     public static String[] dmns;//
    12     public static Class[] mts0;
    13 
    14     public Wrapper1() {
    15     }
    16 
    17     public String[] getPropertyNames() {
    18         return pns;
    19     }
    20 
    21     public boolean hasProperty(String n) {
    22         return pts.containsKey(n);
    23     }
    24 
    25     public Class getPropertyType(String n) {
    26         return (Class) pts.get(n);
    27     }
    28 
    29     public String[] getMethodNames() {
    30         return mns;
    31     }
    32 
    33     public String[] getDeclaredMethodNames() {
    34         return dmns;
    35     }
    36 
    37     public void setPropertyValue(Object o, String n, Object v) {
    38         com.alibaba.dubbo.demo.provider.DemoServiceImpl w;
    39         try {
    40             w = ((com.alibaba.dubbo.demo.provider.DemoServiceImpl) o);
    41         } catch (Throwable e) {
    42             throw new IllegalArgumentException(e);
    43         }
    44         throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property "" + n + "" filed or setter method in class com.alibaba.dubbo.demo.provider.DemoServiceImpl.");
    45     }
    46 
    47     public Object getPropertyValue(Object o, String n) {
    48         com.alibaba.dubbo.demo.provider.DemoServiceImpl w;
    49         try {
    50             w = ((com.alibaba.dubbo.demo.provider.DemoServiceImpl) o);
    51         } catch (Throwable e) {
    52             throw new IllegalArgumentException(e);
    53         }
    54         throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property "" + n + "" filed or setter method in class com.alibaba.dubbo.demo.provider.DemoServiceImpl.");
    55     }
    56 
    57     /**
    58      * @param o  实现类
    59      * @param n  方法名称
    60      * @param p  参数类型
    61      * @param v  参数名称
    62      * @return
    63      * @throws java.lang.reflect.InvocationTargetException
    64      */
    65     public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException {
    66         com.alibaba.dubbo.demo.provider.DemoServiceImpl w;
    67         try {
    68             w = ((com.alibaba.dubbo.demo.provider.DemoServiceImpl) o);
    69         } catch (Throwable e) {
    70             throw new IllegalArgumentException(e);
    71         }
    72         try {
    73             if ("sayHello".equals(n) && p.length == 1) {
    74                 return ($w) w.sayHello((java.lang.String) v[0]);
    75             }
    76         } catch (Throwable e) {
    77             throw new java.lang.reflect.InvocationTargetException(e);
    78         }
    79         throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException("Not found method "" + n + "" in class com.alibaba.dubbo.demo.provider.DemoServiceImpl.");
    80     }
    81 }

    之后创建一个AbstractProxyInvoker实例。

     1 package com.alibaba.dubbo.rpc.proxy;
     2 
     3 import com.alibaba.dubbo.common.URL;
     4 import com.alibaba.dubbo.rpc.Invocation;
     5 import com.alibaba.dubbo.rpc.Invoker;
     6 import com.alibaba.dubbo.rpc.Result;
     7 import com.alibaba.dubbo.rpc.RpcException;
     8 import com.alibaba.dubbo.rpc.RpcResult;
     9 
    10 import java.lang.reflect.InvocationTargetException;
    11 
    12 public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
    13     private final T proxy;
    14     private final Class<T> type;
    15     private final URL url;
    16 
    17     public AbstractProxyInvoker(T proxy, Class<T> type, URL url) {
    18         if (proxy == null) {
    19             throw new IllegalArgumentException("proxy == null");
    20         }
    21         if (type == null) {
    22             throw new IllegalArgumentException("interface == null");
    23         }
    24         if (!type.isInstance(proxy)) {
    25             throw new IllegalArgumentException(proxy.getClass().getName() + " not implement interface " + type);
    26         }
    27         this.proxy = proxy;
    28         this.type = type;
    29         this.url = url;
    30     }
    31 
    32     public Class<T> getInterface() {
    33         return type;
    34     }
    35 
    36     public URL getUrl() {
    37         return url;
    38     }
    39 
    40     public boolean isAvailable() {
    41         return true;
    42     }
    43 
    44     public void destroy() {
    45     }
    46 
    47     public Result invoke(Invocation invocation) throws RpcException {
    48         try {
    49             return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()));
    50         } catch (InvocationTargetException e) {
    51             return new RpcResult(e.getTargetException());
    52         } catch (Throwable e) {
    53             throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e);
    54         }
    55     }
    56 
    57     /**
    58      * 由创建的实例来复写
    59      * @param proxy
    60      * @param methodName
    61      * @param parameterTypes
    62      * @param arguments
    63      * @return
    64      * @throws Throwable
    65      */
    66     protected abstract Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable;
    67 
    68     @Override
    69     public String toString() {
    70         return getInterface() + " -> " + getUrl() == null ? " " : getUrl().toString();
    71     }
    72 }

    其中:

    • proxy: com.alibaba.dubbo.demo.provider.DemoServiceImpl 实例
    • type: interface com.alibaba.dubbo.demo.DemoService Class对象
    • url: injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=3275&side=provider&timestamp=1507010529605

    这样,具体服务就被包装成AbstractProxyInvoker实例了。

    二 AbstractProxyInvoker实例转换为Exporter

    Exporter<?> exporter = protocol.export(invoker);

    调用链如下:

     1                <!--  2 将Invoker暴露为Exporter   -->
     2                -->Protocol$Adaptive.export(Invoker<T> invoker)
     3                   -->ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension("injvm")
     4                   -->ProtocolListenerWrapper.export(Invoker<T> invoker)
     5                      -->ProtocolFilterWrapper.export(Invoker<T> invoker)
     6                         -->buildInvokerChain(final Invoker<T> invoker, key:"service.filter", group:"provider")
     7                            -->ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(injvmUrl, "service.filter", "provider")
     8                         -->InjvmProtocol.export(Invoker<T> invoker)
     9                            -->new InjvmExporter(Invoker<T> invoker, key:"com.alibaba.dubbo.demo.DemoService", Map<String, Exporter<?>> exporterMap)
    10                               -->InjvmExporter.exporterMap({"com.alibaba.dubbo.demo.DemoService" -> "injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=3207&side=provider&timestamp=1507009133930"})
    11                   -->new ListenerExporterWrapper(Exporter<T> exporter, List<ExporterListener> listeners) : 使用listener包装invoker

    1 Protocol$Adaptive.export(Invoker<T> invoker)

     1     public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
     2         if (arg0 == null)
     3             throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
     4         if (arg0.getUrl() == null)
     5             throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
     6         com.alibaba.dubbo.common.URL url = arg0.getUrl();
     7         String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
     8         if(extName == null)
     9             throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
    10         com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
    11         return extension.export(arg0);
    12     }
    • arg0:上边创建出来的AbstractProxyInvoker实例。

    这里,首先是参数检查和赋值。之后获取key为injvm的Protocol实现类:InjvmProtocol,该类会在spi进行aop的时候被ProtocolFilterWrapper和ProtocolListenerWrapper递归包裹,最终调用链为:

    ProxyFactory$Adaptive -> ProtocolListenerWrapper -> ProtocolFilterWrapper -> InjvmProtocol

    2 ProtocolListenerWrapper.export(Invoker<T> invoker)

    1     public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    2         if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
    3             return protocol.export(invoker);
    4         }
    5         return new ListenerExporterWrapper<T>(protocol.export(invoker),
    6                                               Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class).getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
    7     }

    这里先调用ProtocolFilterWrapper.export(Invoker<T> invoker),之后获取listener,最后进行递归包裹。(这里没有listener)

    3 ProtocolFilterWrapper.export(Invoker<T> invoker)

    1     public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    2         if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
    3             return protocol.export(invoker);
    4         }
    5         return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
    6     }

    这里首先使用filter对invoker进行了递归包裹,之后使用InjvmProtocol将包裹后的invoker转化为InjvmExporter。

    buildInvokerChain(final Invoker<T> invoker, String key, String group)

     1     /**
     2      * 1 根据key从url中获取相应的filter的values,再根据这个values和group去获取类上带有@Active注解的filter集合
     3      * 2 之后将这些filter对传入的invoker进行递归包装层invoker(就是一个链表)
     4      */
     5     private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
     6         Invoker<T> last = invoker;
     7         List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
     8         if (filters.size() > 0) {
     9             for (int i = filters.size() - 1; i >= 0; i--) {
    10                 final Filter filter = filters.get(i);
    11                 final Invoker<T> next = last;
    12                 last = new Invoker<T>() {
    13 
    14                     public Class<T> getInterface() {
    15                         return invoker.getInterface();
    16                     }
    17 
    18                     public URL getUrl() {
    19                         return invoker.getUrl();
    20                     }
    21 
    22                     public boolean isAvailable() {
    23                         return invoker.isAvailable();
    24                     }
    25 
    26                     public Result invoke(Invocation invocation) throws RpcException {
    27                         return filter.invoke(next, invocation);
    28                     }
    29 
    30                     public void destroy() {
    31                         invoker.destroy();
    32                     }
    33 
    34                     @Override
    35                     public String toString() {
    36                         return invoker.toString();
    37                     }
    38                 };
    39             }
    40         }
    41         return last;
    42     }

    这里:

    • invoker:之前创建出来的AbstractProxyInvoker实例;
    • key:service.filter
    • group:provider
    List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);

    这句代码,是:根据key从url中获取相应的filter的values,再根据这个values和group去获取类上带有@Active注解的filter集合。这一块儿具体的代码可以查看讲解spi中的loadFile方法。最终会获取到8个filter,关于filter,后续会说。

    4 InjvmProtocol.export(Invoker<T> invoker)

    1     public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    2         return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
    3     }
     1 class InjvmExporter<T> extends AbstractExporter<T> {
     2     private final String key;
     3     private final Map<String, Exporter<?>> exporterMap;
     4 
     5     InjvmExporter(Invoker<T> invoker, String key, Map<String, Exporter<?>> exporterMap) {
     6         super(invoker);
     7         this.key = key;
     8         this.exporterMap = exporterMap;
     9         exporterMap.put(key, this);
    10     }
    11 
    12     public void unexport() {
    13         super.unexport();
    14         exporterMap.remove(key);
    15     }
    16 }

    最终的InjvmExporter实例

    • key = "com.alibaba.dubbo.demo.DemoService"
    • exporterMap: { "com.alibaba.dubbo.demo.DemoService" -> 当前的InjvmExporter实例 }
    • Invoker<T> invoker = 被filter进行递归包裹后的Invoker

    最终的ServiceConfig的exporters列表:

    • List<Exporter<?>> exporters = [ 上边的injvmExporter实例 ]

    为什么要有本地暴露?

    同一个jvm中的服务,相互调用不需要通过远程注册中心,但是又想使用filter链,可以使用本地暴露。

    https://dubbo.gitbooks.io/dubbo-user-book/demos/local-call.html

    “本地调用使用了 injvm 协议,是一个伪协议,它不开启端口,不发起远程调用,只在 JVM 内直接关联,但执行 Dubbo 的 Filter 链。”

  • 相关阅读:
    我爱java系列之---【微服务间的认证—Feign拦截器】
    我爱java系列之---【设置权限的三种解决方案】
    581. Shortest Unsorted Continuous Subarray
    129. Sum Root to Leaf Numbers
    513. Find Bottom Left Tree Value
    515. Find Largest Value in Each Tree Row
    155. Min Stack max stack Maxpop O(1) 操作
    painting house
    Minimum Adjustment Cost
    k Sum
  • 原文地址:https://www.cnblogs.com/java-zhao/p/7623426.html
Copyright © 2020-2023  润新知