• 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 链。”

  • 相关阅读:
    201671010410 冯婷秀 实验三 作业互评与改进
    读《构建之法》感想
    实验十四 团队项目评审&课程学习总结
    201671010412 郭佳 实验四附加实验
    201671010412 郭佳 英文文本统计分析
    201671010412 郭佳 实验二 软件工程个人项目
    201671010412 郭佳 实验三 作业互评与改进
    在阅读《现代软件工程—构建之法》后的思考问题
    金生芳-实验十四 团队项目评审&课程学习总结
    实验四 附加实验-项目互评
  • 原文地址:https://www.cnblogs.com/java-zhao/p/7623426.html
Copyright © 2020-2023  润新知