dubbo源码学习三—暴露服务exporter、invoker

前面我们知道通过自定义标签,我们可以定位到相关标签的解析,同时梳理出三个重要的bean:ServiceBean、ReferenceBean、ConfigCenterBean。
通过Servicebean,可以看到ServiceConfig中有我们关注的export方法。

通过export,我们可以看到其暴露服务,又分为本地暴露和远程暴露两种,而暴露之前,会进行配置的检查,然后进行url的组装操作,接着进行exporter,而暴露之前,会进行getInvoker操作。

在getInvoker操作中,首先会进行适配,然后进行动态代理模板生成,生成class文件。

export操作中,进入到RegisterProtocol中,export又分为暴露doLocalExport(originInvoker, providerUrl)—>protocol.export(invokerDelegate)—>DubboProtocol#export(Invoker invoker),完成配置的放入map之后,进行服务器开启openServer(url),进行双重校验创建服务器createServer(url)—> Exchangers.bind(url, requestHandler)—>getExchanger(url).bind(url, handler)—>HanderExchanger#bind(URL url, ExchangeHandler handler)—>Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler)))—> getTransporter().bind(url, handler)—>NettyTransporter#NettyServer(url, listener)—>NettyServer#doOpen()—>ServerBootstrap# bind(final SocketAddress localAddress),进行配置的和注册、订阅过程。

暴露的过程又是首先进行适配,然后适配之后,进行到dubboProtocol中,进行getInvoker操作。

一、Invoker操作

ProxyFactory#getInvoker(proxy,type,url)

暴露服务invoker包含两个:一个是暴露在本地injvm中的,一个是暴露到远程的,因此就有两个,但两者都会调用invoker操作:

@SPI("javassist")
public interface ProxyFactory {
   //采用的是适配器模式 适配代理的key,获取invoker包含代理和类型和url
   @Adaptive({PROXY_KEY})
   <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;

我们知道invoker在dubbo中是非常重要的。其底层就是动态代理的思想。思考:invoker是什么,同时其能够做什么,同时暴露服务的过程是什么?

invoker:在dubbo中,Invoker是一个非常重要的模型,在服务提供端和服务引用端都会出现invoker.Dubbo官方文档中对Invoker进行了说明:
   invoker是实体域,它是Dubbo的核心模型,其它模型都向它靠拢,或转换成它。它代表一个可执行体,可向它发起invoker调用,它有可能是一个本地的时下,也有可能是一个远程的实现,也有可能一个集群实现。
   Invoker是由ProxyFactory创建而来的,Dubbo默认的ProxyFactory实现类是JavassistProxyFactory。其中有jdkProxyFactory、MockProxyFacotry、JavassistProxyFactory、JavassistProxyFactory等

JavassistProxyFactory#getInvoker(T proxy, Class type, URL url)

因此我们可以查看javassistProxyFactory:

//默认代理方式 javassist的rpc代理工厂方式
public class JavassistProxyFactory extends AbstractProxyFactory {
    //获取invoker
    @Override
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
        //为目标类创建wrapper,此时保存的信息生成好了class文件
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        //抽象匿名Invoker类对象,并实现doInvoker方法
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            //进行invoker
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                //调用wrapper包装类的invokeMethod方法,invokerMethod最终会调用目标方法
                //代理对象、方法名称、参数类型、参数
                //invoker方法中:对实例的class、hashcode、toString、args进行返回
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }

javassistProxyFactory中做了这些事:

1.为目标类创建wrapper,此时保存的信息生成好了class文件
2.抽象匿名Invoker类对象,实现doInvoker方法
3.调用wrapper包装类的invokeMethod反复,invokerMethod最终会调用目标方法
4.invokeMethod方法对实例的class、hashcode、toStrring、args进行返回

Wrapper#getWrapper(Class<?> c)

首先进行getWrapper方法的查看invoker的创建过程

//获取包装对象
//不能包装动态类,如果是动态类,则拿到传入类实例的父类
//如果不是动态类,是Object类,则直接返回包装对象
//否者返回包装的
public static Wrapper getWrapper(Class<?> c) {
    while (ClassGenerator.isDynamicClass(c)) // can not wrapper on dynamic class.
    {
        c = c.getSuperclass();
    }

    if (c == Object.class) {
        return OBJECT_WRAPPER;
    }

    return WRAPPER_MAP.computeIfAbsent(c, key -> makeWrapper(key));
}

进行模板方法的生成。在这个过程中,我们可以看到获取invoekr需要经历以下步骤:

扫描二维码关注公众号,回复: 10877450 查看本文章
1.获取包装对象时,首先如果是动态代理类,则返回传入类的父类
2.如果不是动态类,是Object类,则返直接返回包装对象
3.进行合法包装

Wrapper#makeWrapper

 //进行包装
private static Wrapper makeWrapper(Class<?> c) {
    //检查c是不是基本类型,如果是,则抛出异常
    if (c.isPrimitive()) {
        throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);
    }
    //拿到类的名称、类加载信息、存储的配置信息、invoker信息
    String name = c.getName();
    ClassLoader cl = ClassUtils.getClassLoader(c);
    //c1用于存储setPropertyValue方法代码
    StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
    //c2用于存储getPropertyValue方法代码
    StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
    //c3用于存储invokerMethod方法代码
    StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");

    //生成类型转换代码及异常捕获代码,比如:
    //DemoService w;try{w = (({DemoService) $1); }}catch(Throwable e){throw new IllegalArgumentException(e);}
    c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
    c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
    c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");

    //pts 用于存储成员变量名和类型
    Map<String, Class<?>> pts = new HashMap<>(); // <property name, property types>
    //ms 用来存储方法描述信息和method实例
    Map<String, Method> ms = new LinkedHashMap<>(); // <method desc, Method instance>
    //mns 为方法名列表
    List<String> mns = new ArrayList<>(); // method names.
    //dmns 用于存储定义在当前类中的方法的名称
    List<String> dmns = new ArrayList<>(); // declaring method names.

    /**====================拿到所有公共字段 ==============**/
    // get all public field.
    for (Field f : c.getFields()) {
        //获取名称、类型
        String fn = f.getName();
        Class<?> ft = f.getType();
        // 忽略关键字 static 或 transient 修饰的变量
        if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers())) {
            continue;
        }

        c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");
        c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");
        //key名称、value 类型
        pts.put(fn, ft);
    }

    //拿到方法
    Method[] methods = c.getMethods();
    // get all public method.

    /**=============拿到所有公共方法   ====================**/
    boolean hasMethod = hasMethods(methods);
    //检查c中是否包含在当前类中声明的方法
    if (hasMethod) {
        c3.append(" try{");
        for (Method m : methods) {
            //ignore Object's method.
            //忽略Object中定义的方法
            if (m.getDeclaringClass() == Object.class) {
                continue;
            }

            String mn = m.getName();
            //生成方法名判断语句
            c3.append(" if( \"").append(mn).append("\".equals( $2 ) ");
            int len = m.getParameterTypes().length;
            //生成运行时转入的参数数量和方法参数类表长度判断语句:比如:&& $3.length == 2
            c3.append(" && ").append(" $3.length == ").append(len);

            boolean override = false;
            //检测方法是否存在重载情况,条件为:方法对象不同&&方法名相同
            for (Method m2 : methods) {
                if (m != m2 && m.getName().equals(m2.getName())) {
                    override = true;
                    break;
                }
            }
            //对重载方法进行处理,考虑下面的方法:
            //1.void sayHello(Integer,String)
            //2.void sayHello(Integer,Integer)
            //方法名相同,参数列表长度也相同,因此不能仅通过这两项判断两个方法是否相等
            //需要进一步判断方法的参数类型
            if (override) {
                if (len > 0) {
                    for (int l = 0; l < len; l++) {
                        //生成参数类型进行检测代理,比如:&& $3[0].getName().equals("java.lang.Integer")
                        //&& $3[1].getName().equals("java.lang.String")
                        c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"")
                            .append(m.getParameterTypes()[l].getName()).append("\")");
                    }
                }
            }

            //添加){,完成方法判断语句,此时生成的代码可能如下(已格式化):
            /**
                 * if ("sayHello".equals($2)
                   && $3.length == 2
                   && $3[0].getName().equals("java.lang.Integer")
                   && $3[1].getName().equals("java.lang.String")) {
                 */
            c3.append(" ) { ");
            //根据返回值类型生成目标方法调用语句
            if (m.getReturnType() == Void.TYPE) {
                //w.sayHello((java.lang.Integer)$4[0],
                //(java.lang.String)$4[1]); return null;
                c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;");
            } else {
                // return w.sayHello((java.lang.Integer)$4[0],
                // (java.lang.String)$4[1]);
                c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");");
            }


            // 添加 }, 生成的代码形如(已格式化):
            // if ("sayHello".equals($2)
            // && $3.length == 2
            // && $3[0].getName().equals("java.lang.Integer")
            // && $3[1].getName().equals("java.lang.String")) {
            //
            // w.sayHello((java.lang.Integer)$4[0],
            //               (java.lang.String)$4[1]);
            // return null;
            // }
            c3.append(" }");

            //添加方法名到 mns 集合中
            mns.add(mn);
            // 检测当前方法是否在 c 中被声明的
            if (m.getDeclaringClass() == c) {
                //如果是,则添加到dmns的list集合中
                dmns.add(mn);
            }
            ms.put(ReflectUtils.getDesc(m), m);
        }
        //添加异常捕获语句
        c3.append(" } catch(Throwable e) { ");
        c3.append("     throw new java.lang.reflect.InvocationTargetException(e); ");
        c3.append(" }");
    }

    // 添加 NoSuchMethodException 异常抛出代码
    c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }");

    /**================处理get/set方法 ==============**/
    // deal with get/set method.
    //处理 get/set方法
    Matcher matcher;
    for (Map.Entry<String, Method> entry : ms.entrySet()) {
        String md = entry.getKey();
        Method method = entry.getValue();
        // 匹配以 get 开头的方法
        if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
            String pn = propertyName(matcher.group(1));
            // 生成属性判断以及返回语句,示例如下:
            // if( $2.equals("name") ) { return ($w).w.getName(); }
            c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
            pts.put(pn, method.getReturnType());
            // 匹配以 is/has/can 开头的方法
        } else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) {
            String pn = propertyName(matcher.group(1));
            // 生成属性判断以及返回语句,示例如下:
            // if( $2.equals("dream") ) { return ($w).w.hasDream(); }
            c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
            pts.put(pn, method.getReturnType());
            // 匹配以 set 开头的方法
        } else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
            Class<?> pt = method.getParameterTypes()[0];
            String pn = propertyName(matcher.group(1));
            // 生成属性判断以及 setter 调用语句,示例如下:
            // if($2.equals("name")) {
            // w.setName((java.lang.String)$3);
            // return;
            // }
            c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt, "$3")).append("); return; }");
            pts.put(pn, pt);
        }
    }
    // 添加 NoSuchPropertyException 异常抛出代码
    c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" field or setter method in class " + c.getName() + ".\"); }");
    c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" field or setter method in class " + c.getName() + ".\"); }");

    /**===================包装类信息 make class=================**/
    // make class
    long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
    //创建类生成器
    ClassGenerator cc = ClassGenerator.newInstance(cl);
    //设置类名和超类
    cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
    cc.setSuperClass(Wrapper.class);
    //添加默认构造函数
    cc.addDefaultConstructor();
    //添加字段
    cc.addField("public static String[] pns;"); // property name array.
    cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.
    cc.addField("public static String[] mns;"); // all method name array.
    cc.addField("public static String[] dmns;"); // declared method name array.
    for (int i = 0, len = ms.size(); i < len; i++) {
        cc.addField("public static Class[] mts" + i + ";");
    }
    //添加方法代码
    cc.addMethod("public String[] getPropertyNames(){ return pns; }");
    cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");
    cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");
    cc.addMethod("public String[] getMethodNames(){ return mns; }");
    cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");
    cc.addMethod(c1.toString());
    cc.addMethod(c2.toString());
    cc.addMethod(c3.toString());

    try {
        //生成类
        Class<?> wc = cc.toClass();
        // setup static field.
        //设置静态字段值
        wc.getField("pts").set(null, pts);
        wc.getField("pns").set(null, pts.keySet().toArray(new String[0]));
        wc.getField("mns").set(null, mns.toArray(new String[0]));
        wc.getField("dmns").set(null, dmns.toArray(new String[0]));
        int ix = 0;
        for (Method m : ms.values()) {
            wc.getField("mts" + ix++).set(null, m.getParameterTypes());
        }
        //场景wrapper实例
        return (Wrapper) wc.newInstance();
    } catch (RuntimeException e) {
        throw e;
    } catch (Throwable e) {
        throw new RuntimeException(e.getMessage(), e);
    } finally {
        cc.release();
        ms.clear();
        mns.clear();
        dmns.clear();
    }
}

生成模板:

1.进行初始化操作:创建c1、c2、c3以及pts、ms、mns等变量,以及向c1、c2、c3中添加方法定义和类型转换代码
2.public 级别的字段生成条件判断取值与赋值代码
3.为定义在当前类中的方法生成判断语句,和方法调用语句
4.用于处理getter、setter 以及以 is/has/can 开头的方法。处理方式是通过正则表达式获取方法类型(get/set/is/...),以及属性名
5.为属性名生成判断语句
6.为方法生成调用语句
7.通过 ClassGenerator 为刚刚生成的代码构建 Class 类,并通过反射创建对象。ClassGenerator 是 Dubbo 自己封装的,该类的核心是 toClass() 的重载方法toClass(ClassLoader, ProtectionDomain),该方法通过 javassist 构建 Class。

Wrapper#invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args)

#invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args)

进行invokerMethod方法的查看:

public abstract class Wrapper {
    //invoker方法
    abstract public Object invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args) throws NoSuchMethodException, InvocationTargetException;
    
//invoke方法
//invoker方法中:对实例的class、hashcode、toString、args进行返回
@Override
public Object invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args) throws NoSuchMethodException {
    if ("getClass".equals(mn)) {
        return instance.getClass();
    }
    if ("hashCode".equals(mn)) {
        return instance.hashCode();
    }
    if ("toString".equals(mn)) {
        return instance.toString();
    }
    if ("equals".equals(mn)) {
        if (args.length == 1) {
            return instance.equals(args[0]);
        }
        throw new IllegalArgumentException("Invoke method [" + mn + "] argument number error.");
    }
    throw new NoSuchMethodException("Method [" + mn + "] not found.");
}

invokerMethod方法中:对实例的class、hashcode、toString、args进行返回。invoker操作完成之后,就可以看服务暴露到本地和服务暴露到远程的操作了。

二、暴露服务到本地

ServiceConfig#exportLocal(URL url)

//暴露服务到本地
//如果url的协议头等于injvm,则说明已经暴露服务到本地了,无需再次暴露
private void exportLocal(URL url) {
    URL local = URLBuilder.from(url)
            //设置协议头为injvm
            .setProtocol(LOCAL_PROTOCOL)
            .setHost(LOCALHOST_VALUE)
            .setPort(0)
            .build();
    //重要 Invoker ,关注getInvoker和export方法
    //创建invoker,并暴露服务,这里的protocol会在运行时调用InjvmProtocol的export方法
    Exporter<?> exporter = PROTOCOL.export(
            PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, local));
    exporters.add(exporter);
    logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry url : " + local);
}

Protocol#export(Invoker invoker)

//SPI扩展
@SPI("dubbo")
public interface Protocol {
    //采用适配器方式进行匹配暴露服务 采用RegisterProtocol,然后进行dubbo协议 dubboProtocol
    //本地适配InjvmProtocol
    @Adaptive
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
 }   

InjvmProtocol# exportLocal(URL url)

public class InjvmProtocol extends AbstractProtocol implements Protocol {
    //injvm暴露服务的方式 服务暴露到本地
    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        //创建InjvmExporter
        return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
    }
}

InjvmExporter的构造方法

//构造方法,包含信息:invoker、key、exporterMap
InjvmExporter(Invoker<T> invoker, String key, Map<String, Exporter<?>> exporterMap) {
    //抽象服务暴露,对其进行校验不为空、invoker、interface、url都不为空
    super(invoker);
    this.key = key;
    this.exporterMap = exporterMap;
    //exporterMap中放着key、key与exporterMap
    exporterMap.put(key, this);
}

暴露到本地exportLocal:

1.拿到协议头为injvm,同时构建url信息

2.在上面我们已经看到器构建好getInvoker的过程其实是一个采用动态代理,这里采用javassistProxyFactory进行getInvoker。其中会对c进行包装,而包装的过程会成模板方法,也即模板方法的class文件,这个过程重点关注makeWrapper。并拿到相关参数进行返回:class、hashcode、toString、args。

3.暴露到本地:这个过程主要是进行协议url的构建,同时进行协议进行getInvoker,再进行export.采用SPI的扩展方式进行适配协议 InjvmProtocol。而远程采用RegisterProtocol进行适配。主要包括参数key和相关的参数信息,会放入到map中。

三、服务暴露到远程

由于代码比较多,这里先梳理思路,再看源码

首先进入到export时,先进行registerProtocol,再接着进入到dubboProtocol。这个过程:
1.首先进行采用适配器方式进行匹配协议RegisterProtoco
2获取注册中心 URL ,获取注册的服务提供者URL,获取订阅url,创建订阅服务监听器
3.暴露invoker,远程暴露服务:
 1)首先进行通过传入的invoker看是否可以拿到缓存key
 2)如果能拿到,则直接访问缓存,创建invoker委托类对象invokerDelegate
 3)调用Protocol的export方法暴露服务,这里适配调用dubboProtocol#export方法
 4)通过invoekr拿到url信息,拿到url之后,获取服务标识:服务组名、服务名、服务版本号、端口号。类似  demoGroup/com.alibaba.dubbo.demo.DemoService:1.0.1:20880. 
 5)创建dubboExporter,<key,exporter>键值对放入到缓存中,里面包含了很多的信息,包括url的信息
 6)本地存根:通过url获取参数信息:stubEvent、DefaultStub、isCallBackService,拿到本地存根事件方法参数信息
 7)启动服务器openServer
     (1)从url中获取服务的地址信息(host:port),并将其作为服务器实例的key,用于标识当前的服务器实例,如果是服务器,则采用双重校验锁的方式进行服务器实例的创建serverMap.put(key, createServer(url));
     (2)如果服务为空,则创建服务,1.检测是否存在server参数锁表示的Transporter扩展,2.创建服务器实例,3.检测是否支持client参数所表示的Transporter扩展
      (3)添加相关参数信息,创建ExchangerServer,也即进行bind操作
      (4)获取Exchanger,默认为HeaderExchanger,紧接着调用HeaderExchanger的bind方法创建ExchangerServer实例
      (5)进行绑定参照,返回的是消息服务器,这采用HandlerExchanger
      (6)首先进行非空校验,校验完之后,进行绑定操作Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler)))
      (6)对传入的url和handlers进行非空校验,如果handlers只有一个,则取第一个,如果大于1,则创建channelHandler分发器,获取适配的Transporter实例,并调用实例方法
       (7)创建NettyServer,调用父类构造方法,调用父类构造方法,获取ip和端口信息,获取最大可接受连接数,闲置超时时间,调用模板方法doOpen启动服务器
       (8)创建boss和worker线程池,创建ServerBoostrap、设置PipelinFactory、绑定到指定的ip和端口上
 8)优化序列化
4.注册服务到注册中心

RegisterProtocol#export方法

//SPI扩展
@SPI("dubbo")
public interface Protocol {
    //采用适配器方式进行匹配暴露服务 采用RegisterProtocol,然后进行dubbo协议 dubboProtocol
    @Adaptive
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;

    //注册协议 暴露服务 远程
    /**=================远程暴露,做两件事,一是做服务的远程暴露,二是进行服务注册,在服务中心注册服务================**/
    @Override
    public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
        //获取注册中心 URL ,以zookeeper注册中心为例,得到的示例URL如下:
        /**
         * zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?
         * application=demo-provider&dubbo=2.0.2&export=dubbo%3A%2F%2F172.17.48.52%3A20880%2F
         * com.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider
         */
        URL registryUrl = getRegistryUrl(originInvoker);
        // url to export locally
        //获取已注册的服务提供者URL ,比如:
        /**
         * dubbo://172.17.48.52:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&
          application=demo-provider&dubbo=2.0.2&generic=false&interface=
          com.alibaba.dubbo.demo.DemoService&methods=sayHello
         */
        URL providerUrl = getProviderUrl(originInvoker);

        // Subscribe the override data
        // FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call
        //  the same service. Because the subscribed is cached key with the name of the service, it causes the
        //  subscription information to cover.
        //获取订阅url
        /**
         * provider://172.17.48.52:20880/com.alibaba.dubbo.demo.DemoService?category=c
           onfigurators&check=false&anyhost=true&application=demo-provider&
           dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello
         */
        final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
        //创建监听器
        final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
        overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);

        providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
        //export invoker
        /**=================暴露 invoker ====================**/
        //暴露invoker,远程暴露服务 重要
        final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);

        /**===============注册到注册中心**+==================**/
        // url to registry
        final Registry registry = getRegistry(originInvoker);
        final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);
        // decide if we need to delay publish
        boolean register = providerUrl.getParameter(REGISTER_KEY, true);
        if (register) {
            register(registryUrl, registeredProviderUrl);
        }

        // Deprecated! Subscribe to override rules in 2.6.x or before.
        //向注册中心进行订阅Overrider数据
        registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
        //设置注册服务提供者url、设置获取订阅服务url
        exporter.setRegisterUrl(registeredProviderUrl);
        exporter.setSubscribeUrl(overrideSubscribeUrl);
        //notify暴露
        notifyExport(exporter);
        //Ensure that a new exporter instance is returned every time export
        //确保这是一个每次暴露的都是一个新的暴露服务实例
        //创建并返回 DestroyableExporter
        return new DestroyableExporter<>(exporter);
    }
}

dubboProtocol#exportChangeableWrapper#export(Invoker invoker)方法

 //做服务暴露 localexport
    @SuppressWarnings("unchecked")
    private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker, URL providerUrl) {
        //通过invoker拿到key
        String key = getCacheKey(originInvoker);
        //访问缓存,创建invoker委托类对象
        return (ExporterChangeableWrapper<T>) bounds.computeIfAbsent(key, s -> {
            Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl);
            /**=========================进行暴露包装 ==========================**/
            //调用protocol的export方法暴露服务 重要
            return new ExporterChangeableWrapper<>((Exporter<T>) protocol.export(invokerDelegate), originInvoker);
        });
    }

 //采用适配器方式进行匹配暴露服务 采用RegisterProtocol,然后进行dubbo协议 dubboProtocol
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;

 //远服务暴露 dubbo协议
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    URL url = invoker.getUrl();

    // export service.
    //暴露服务
    //获取服务标识,理解成服务坐标也行。由服务组名、服务名、服务版本号以及端口组成。比如:
    //demoGroup/com.alibaba.dubbo.demo.DemoService:1.0.1:20880
    String key = serviceKey(url);
    //创建DubboExporter
    DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
    //将<key,exporter> 键值对放入缓存中
    exporterMap.put(key, exporter);

    //export an stub service for dispatching event
    //暴露本地存根服务 转发事件
    //本地存根相关代码
    //获取参数信息:stubEvent、DefaultStub、isCallBackService
    Boolean isStubSupportEvent = url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT);
    Boolean isCallbackservice = url.getParameter(IS_CALLBACK_SERVICE, false);
    if (isStubSupportEvent && !isCallbackservice) {
        //拿到本地存根事假服务参数信息
        String stubServiceMethods = url.getParameter(STUB_EVENT_METHODS_KEY);
        if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
            if (logger.isWarnEnabled()) {
                logger.warn(new IllegalStateException("consumer [" + url.getParameter(INTERFACE_KEY) +
                                                      "], has set stubproxy support event ,but no stub methods founded."));
            }

        }
    }
    /**=============启动服务 =============**/
    //启动服务器  重要关注
    openServer(url);
    //优化序列化
    optimizeSerialization(url);

    return exporter;
}

接着我们看启动服务做了什么

DubboProtocol#openServer(url)#createServer(URL url)bind(url, requestHandler)

//从url中获取服务的地址信息(host:port)、并将其作为服务器实例的key,用于标识当前的服务器实例
private void openServer(URL url) {
    // find server.
    String key = url.getAddress();
    //client can export a service which's only for server to invoke
    boolean isServer = url.getParameter(IS_SERVER_KEY, true);
    if (isServer) {
        //访问缓存
        ProtocolServer server = serverMap.get(key);
        //使用双重校验锁
        if (server == null) {
            synchronized (this) {
                /**-============重要  创建服务器实例createServer(url)===============**/
                //创建服务器实例
                server = serverMap.get(key);
                if (server == null) {
                    serverMap.put(key, createServer(url));
                }
            }
        } else {
            // server supports reset, use together with override
            //服务器已创建,则根据url中的配置重置服务器
            server.reset(url);
        }
    }
}


//如果服务为空,则创建服务
// 1.检测是否存在server参数锁表示的Transporter扩展
// 2.创建服务器实例
// 3.检测是否支持client参数所表示的Transporter扩展
private ProtocolServer createServer(URL url) {
    url = URLBuilder.from(url)
        // send readonly event when server closes, it's enabled by default
        //当服务器关闭的时候,发送只读事件
        .addParameterIfAbsent(CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString())
        // enable heartbeat by default
        //添加心跳 默认
        .addParameterIfAbsent(HEARTBEAT_KEY, String.valueOf(DEFAULT_HEARTBEAT))
        //添加编码解码器参数
        .addParameter(CODEC_KEY, DubboCodec.NAME)
        .build();
    //拿到server的key和远程默认的服务器netty,获取server参数
    String str = url.getParameter(SERVER_KEY, DEFAULT_REMOTING_SERVER);
    //通过SPI检测是否存在server参数所代表的Transporter扩展,不存在则抛异常
    if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {
        throw new RpcException("Unsupported server type: " + str + ", url: " + url);
    }

    ExchangeServer server;
    try {
        /**-==========================重要 进行bind操作 ====================**/
        //创建ExchangerServer  重要
        server = Exchangers.bind(url, requestHandler);
    } catch (RemotingException e) {
        throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
    }
    //拿到client参数,可以指定netty、mina
    str = url.getParameter(CLIENT_KEY);
    if (str != null && str.length() > 0) {
        //获取所以的Transporter实现类名称集合,比如supportedType=[netty,mina]
        Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
        //检测当前dubbo所支持的Transporter实现类名称列表中,是否包含client所表示的Transporter,若不包含,则抛出异常
        if (!supportedTypes.contains(str)) {
            throw new RpcException("Unsupported client type: " + str);
        }
    }

    return new DubboProtocolServer(server);
}

如果服务为空,则创建服务
1.检测是否存在server参数锁表示的Transporter扩展
2.创建服务器实例
3.检测是否支持client参数所表示的Transporter扩展

进行服务器绑定

Exchanger#bind(url, requestHandler)

/**=================Exchangers 绑定服务操作 ===================**/
//做服务器绑定操作
public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
    if (url == null) {
        throw new IllegalArgumentException("url == null");
    }
    if (handler == null) {
        throw new IllegalArgumentException("handler == null");
    }
    url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange");
    //获取Exchanger,默认为HeaderExchanger,紧接着调用HeaderExchanger的bind方法创建ExchangerServer实例
    //查看HeaderExchangerServer  重要
    return getExchanger(url).bind(url, handler);
}

 //进行绑定参照,返回的是消息服务器,这里调试采用HandlerExchanger
@Adaptive({Constants.EXCHANGER_KEY})
ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException;

 /*****==============重要  绑定bind 消息服务器操作 ==============**/
//返回消息服务器
@Override
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
    //包含url、handler
    //创建HeaderExchangeServer实例,该方法包含了多个逻辑,分别如下:
    //1.new HeaderExchangeHeader(handler)
    //2.new DecodeHandler(new HeaderExchangeHandler(handler))
    //3.Transporters.bind(url,new DecodeHandler(new HanderExchangeHandler(handler)))
    //首先进行ChannelHandler非空校验,接着解码handler时进行ChannelHandler非空校验
    //校验完之后,进行绑定操作  bind操作 重要
    return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}

Transporters#bind(URL url, ExchangeHandler handler)

//消息服务器
public static RemotingServer bind(URL url, ChannelHandler... handlers) throws RemotingException {
    //进行非空校验 url和handler不为空
    if (url == null) {
        throw new IllegalArgumentException("url == null");
    }
    if (handlers == null || handlers.length == 0) {
        throw new IllegalArgumentException("handlers == null");
    }
    ChannelHandler handler;
    //如果长度为1,则取第一个
    if (handlers.length == 1) {
        handler = handlers[0];
    } else {
        //如果handler的元素长度大于1,则创建channelHandler分发器
        handler = new ChannelHandlerDispatcher(handlers);
    }
    //获取自适应Transporter实例,并调用实例方法
    return getTransporter().bind(url, handler);
}

@SPI("netty")
public interface Transporter {
 //采用适配器的方式进行适配
    @Adaptive({Constants.SERVER_KEY, Constants.TRANSPORTER_KEY})
    RemotingServer bind(URL url, ChannelHandler handler) throws RemotingException;
}

public class NettyTransporter implements Transporter {
    //进行nettyTransporter
    @Override
    public RemotingServer bind(URL url, ChannelHandler listener) throws RemotingException {
        //创建NettyServer
        return new NettyServer(url, listener);
  }
}  
   
public class NettyServer extends AbstractServer implements RemotingServer {
     public NettyServer(URL url, ChannelHandler handler) throws RemotingException {
        //调用父类构造方法
        super(ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME), ChannelHandlers.wrap(handler, url));
    }
    
      //抽象服务 nettyServer
    public AbstractServer(URL url, ChannelHandler handler) throws RemotingException {
        //调用父类构造方法
        super(url, handler);
        localAddress = getUrl().toInetSocketAddress();
        //获取ip和端口信息
        String bindIp = getUrl().getParameter(Constants.BIND_IP_KEY, getUrl().getHost());
        int bindPort = getUrl().getParameter(Constants.BIND_PORT_KEY, getUrl().getPort());
        if (url.getParameter(ANYHOST_KEY, false) || NetUtils.isInvalidLocalHost(bindIp)) {
            //设置ip为0.0.0.0
            bindIp = ANYHOST_VALUE;
        }
        bindAddress = new InetSocketAddress(bindIp, bindPort);
        //获取最大可接受连接数
        this.accepts = url.getParameter(ACCEPTS_KEY, DEFAULT_ACCEPTS);
        //闲置超时时间
        this.idleTimeout = url.getParameter(IDLE_TIMEOUT_KEY, DEFAULT_IDLE_TIMEOUT);
        try {
            /**=====================重要 doOpen操作==============**/
            //调用模板方法doOpen启动服务器  重点
            doOpen();
            if (logger.isInfoEnabled()) {
                logger.info("Start " + getClass().getSimpleName() + " bind " + getBindAddress() + ", export " + getLocalAddress());
            }
        } catch (Throwable t) {
            throw new RemotingException(url.toInetSocketAddress(), null, "Failed to bind " + getClass().getSimpleName()
                    + " on " + getLocalAddress() + ", cause: " + t.getMessage(), t);
        }
        executor = executorRepository.createExecutorIfAbsent(url);
    }
}   

public abstract class AbstractServer extends AbstractEndpoint implements RemotingServer {
  protected abstract void doOpen() throws Throwable;
}

//NettyServer
public class NettyServer extends AbstractServer implements RemotingServer { 
    @Override
    protected void doOpen() throws Throwable {
        NettyHelper.setNettyLoggerFactory();
        //创建boss和worker线程池
        ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true));
        ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true));
        ChannelFactory channelFactory = new NioServerSocketChannelFactory(boss, worker, getUrl().getPositiveParameter(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS));
        //创建serverBootStrap
        bootstrap = new ServerBootstrap(channelFactory);

        final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
        channels = nettyHandler.getChannels();
        // https://issues.jboss.org/browse/NETTY-365
        // https://issues.jboss.org/browse/NETTY-379
        // final Timer timer = new HashedWheelTimer(new NamedThreadFactory("NettyIdleTimer", true));
        bootstrap.setOption("child.tcpNoDelay", true);
        bootstrap.setOption("backlog", getUrl().getPositiveParameter(BACKLOG_KEY, Constants.DEFAULT_BACKLOG));
        //设置PipelineFactory
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            @Override
            public ChannelPipeline getPipeline() {
                NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
                ChannelPipeline pipeline = Channels.pipeline();
                /*int idleTimeout = getIdleTimeout();
                if (idleTimeout > 10000) {
                    pipeline.addLast("timer", new IdleStateHandler(timer, idleTimeout / 1000, 0, 0));
                }*/
                pipeline.addLast("decoder", adapter.getDecoder());
                pipeline.addLast("encoder", adapter.getEncoder());
                pipeline.addLast("handler", nettyHandler);
                return pipeline;
            }
        });
        // bind
        //绑定到指定的ip和端口上
        channel = bootstrap.bind(getBindAddress());
    }
}  

//绑定到指定的ip和端口上
public class ServerBootstrap extends Bootstrap {
   public Channel bind(final SocketAddress localAddress) {
       //进行非空校验
        if (localAddress == null) {
            throw new NullPointerException("localAddress");
        }

        final BlockingQueue<ChannelFuture> futureQueue =
            new LinkedBlockingQueue<ChannelFuture>();

        ChannelHandler binder = new Binder(localAddress, futureQueue);
        ChannelHandler parentHandler = getParentHandler();

        ChannelPipeline bossPipeline = pipeline();
       //bossPineline
        bossPipeline.addLast("binder", binder);
        if (parentHandler != null) {
            bossPipeline.addLast("userHandler", parentHandler);
        }

        Channel channel = getFactory().newChannel(bossPipeline);

        // Wait until the future is available.
        ChannelFuture future = null;
        boolean interrupted = false;
        do {
            try {
                future = futureQueue.poll(Integer.MAX_VALUE, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                interrupted = true;
            }
        } while (future == null);

        if (interrupted) {
            Thread.currentThread().interrupt();
        }

        // Wait for the future.
        future.awaitUninterruptibly();
        if (!future.isSuccess()) {
            future.getChannel().close().awaitUninterruptibly();
            throw new ChannelException("Failed to bind to: " + localAddress, future.getCause());
        }

        return channel;
    }
}

学习完成服务暴露和getInvoker之后,后续进行服务注册和订阅学习。

发布了28 篇原创文章 · 获赞 5 · 访问量 8165

猜你喜欢

转载自blog.csdn.net/trytostudy/article/details/105563223