Dubbo provider export 的 invoker到底是什么?

文章目录

  • 拾遗
  • 总结


拾遗

JavassistProxyFactory.getInvoker

final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf(36) < 0 ? proxy.getClass() : type);

getWrapper->ret = makeWrapper©;

Wrapper var50 = (Wrapper)wc.newInstance();这一行打断点,实例化之前。Dubbo provider export 的 invoker到底是什么?_第1张图片
得到

public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException{ com.leesin.ISayHelloService w; try{ w = ((com.leesin.ISayHelloService)$1); }catch(Throwable e){ throw new IllegalArgumentException(e); } try{ if( "sayHello".equals( $2 )  &&  $3.length == 0 ) {  return ($w)w.sayHello(); } if( "sayByeBye".equals( $2 )  &&  $3.length == 0 ) {  return ($w)w.sayByeBye(); } } catch(Throwable e) {      throw new java.lang.reflect.InvocationTargetException(e);  } throw new org.apache.dubbo.common.bytecode.NoSuchMethodException("Not found method \""+$2+"\" in class com.leesin.ISayHelloService."); }

格式化一下

package com.leesin;

/**
 * @description:
 * @author: Leesin Dong
 * @date: Created in 2020/4/30 23:50
 * @modified By:
 */
public class Test {
    public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException {
        com.leesin.ISayHelloService w;
        try {
            w = ((com.leesin.ISayHelloService) $1);
        } catch (Throwable e) {
            throw new IllegalArgumentException(e);
        }
        try {
            if ("sayHello".equals($2) && $3.length == 0) {
                return ($w) w.sayHello();
            }
            if ("sayByeBye".equals($2) && $3.length == 0) {
                return ($w) w.sayByeBye();
            }
        } catch (Throwable e) {
            throw new java.lang.reflect.InvocationTargetException(e);
        }
        throw new org.apache.dubbo.common.bytecode.NoSuchMethodException("Not found method \"" + $2 + "\" in class com.leesin.ISayHelloService.");
    }
}

根据方法明和参数的长度匹配方法,从而直接调用方法。

可以看到发布invoker其实相当于把当前配置的server注解中对应的实例中的所有方法进行了发布,方法封装在了invoker中。

所以在consumer中
AbstractClusterInvoker的invoke中

List<Invoker<T>> invokers = list(invocation);

最终调用到路由

public List<Invoker<T>> route(URL url, Invocation invocation) {
        List<Invoker<T>> finalInvokers = invokers;
        for (Router router : routers) {//三种路由:条件路由、脚本路由、标签路由(tag)
            //所以做三次循环,经过三个路由,最终得到一个invokerlist
            finalInvokers = router.route(finalInvokers, url, invocation);
        }
        return finalInvokers;
    }

一直在想为什么没有对方法进行匹配?值从Directory中拿到invokers,而这个invokers是从provideruri中拿到的,而这个provideruri是基于subscribe(consumeruri)中的category:provider得到的,所以provideruri是和接口对应的,所以provideruri会拿到接口对应的所有的invoker,这个invoker可能是provider端提供的,在不同机器上发布的同一种实现,也可能是在同一机器上或者不同机器上的不同实现,但是都是基于同一个接口的,而在真实调用的时候会在provider的invoker中进行if判断的调用的到底是哪个方法,所以在consumer是不用判断的,而不同的uri只是zk provider节点下的节点(这些节点就是),会被监听,然后放到RoutChain中,所以只需要根据路由进行一个filter,选出一类可能需要的invoker,在做后续的处理。

统一接口的不同实现:

在这里插入图片描述

总结

provider invoker 就是DelegateProviderMetaInvoker(AbstractProxyInvoker),AbstractProxyInvoker中将实现类通过javassist进行转变,变成 根据方法名和参数长度进行判断到底调用哪个方法 的类,以后调用具体方法,其实调用的是wrapper.invokeMethod即根据方法名和参数长度进行判断到底调用哪个方法

provider的 invoker 可以分成多个 :一个接口的多个实现分布再一个或多个机器上,而这些会循环所有registry中的zk进行注册到providers节点

consumer的 动态代理类的invoke方法会通过rout对这个接口所有订阅的provider进行过滤。而过滤中不需要进行类名或者方法名的匹配,因为本身就可以是多个实现,我并不关心也对我不是透明的,所以这个rout相当于只对发布者的ip port感兴趣,而方法会在provider调用的时候根据invocation中的method的名字参数进行匹配。

你可能感兴趣的:(#,Dubbo)