JavassistProxyFactory.getInvoker
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf(36) < 0 ? proxy.getClass() : type);
getWrapper->ret = makeWrapper©;
在Wrapper var50 = (Wrapper)wc.newInstance();
这一行打断点,实例化之前。
得到
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的名字参数进行匹配。