概述
在分析服务暴露和服务引用的都提到ProxyFactory,它是Dubbo的代理工厂,只定义了两个方法。
- getInvoker,暴露服务时调用,将ref(真正的服务实现类)转化为Invoker
- getProxy,引用服务时调用,将Invoker对象转化为proxy代理对象
Invoker
Invoker 是 Dubbo 领域模型中非常重要的一个概念,很多设计思路都是向它靠拢。这就使得 Invoker 渗透在整个实现代码里,对于刚开始接触 Dubbo 的人,确实容易给搞混了。 下面我们用一个精简的图来说明最重要的两种 Invoker:服务提供 Invoker 和服务消费 Invoker:
上面是出自Dubbo的官方教程。
服务提供端的AbstractProxyInvoker,封装了真正的服务实现类,代理了它的方法。服务消费端的DubboInvoker等,封装了远程通信的逻辑。
Dubbo中对远程的调用是Invoker,调用服务真正的实现类也是Invoker。
ProxyFactory
Dubbo的代理工厂,Dubbo之所以能够宣传像调用本地服务一样调用远程服务,就是用它实现的。@SPI扩展接口,默认实现是JavassistProxyFactory,还有一个实现是JdkProxyFactory,最终都会被StubProxyFactoryWrapper包装。
@SPI("javassist")
public interface ProxyFactory {
/**
* 服务引用时调用
* create proxy.
*
* @param invoker Protocol生成的Invoker
* @return proxy
*/
@Adaptive({Constants.PROXY_KEY})
<T> T getProxy(Invoker<T> invoker) throws RpcException;
/**
* 服务暴露时调用
* create invoker.
*
* @param <T>
* @param proxy Service对象
* @param type Service类型
* @param url
* @return invoker
*/
@Adaptive({Constants.PROXY_KEY})
<T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
}
getInvoker
JavassistProxyFactory和JdkProxyFactory的返回的都是AbstractProxyInvoker,区别在于前者使用自动生成的类,包装了硬编码进行调用,后者则使用JDK反射机制进行调用。对于Dubbo来说都是Invoker,进行了统一的抽象,这样Dubbo框架就不需要关心服务的具体业务,全部交给AbstractProxyInvoker去封装。
真正调用服务的时候会执行Invoker#invoke(),而AbstractProxyInvoker会把调用转给真正的服务实现类。
JavassistProxyFactory
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// TODO Wrapper类不能正确处理带$的类名
// TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
// proxy.getClass()返回的是实现类的Class,type是接口的Class
// Wrapper对象对方法的调用进行了包装,没有使用反射,
// Wrapper是使用javassist动态生成类才进行方法调用的包装
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
某个Wrapper类的代码片段,没有用反射
public Object invokeMethod(Object var1, String var2, Class[] var3, Object[] var4) throws InvocationTargetException {
DemoService var5;
try {
var5 = (DemoService)var1;
} catch (Throwable var8) {
throw new IllegalArgumentException(var8);
}
try {
if ("sayHello".equals(var2) && var3.length == 1) {
return var5.sayHello((String)var4[0]);
}
} catch (Throwable var9) {
throw new InvocationTargetException(var9);
}
throw new NoSuchMethodException("Not found method \"" + var2 + "\" in class cre.dubbo.demo.DemoService.");
}
JdkProxyFactory
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
// 使用反射调用
Method method = proxy.getClass().getMethod(methodName, parameterTypes);
return method.invoke(proxy, arguments);
}
};
}
getProxy
生成的代理类实现指定的服务接口(还会实现EchoService接口),因此消费端在使用代理对象的时候跟使用本地服务是一样的。JavassistProxyFactory和JdkProxyFactory的都使用到了InvokerInvocationHandler,
InvokerInvocationHandler它的作用是将消费端的调用转到内部的Invoker#invoke()上
JavassistProxyFactory
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
JdkProxyFactory
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
}
InvokerInvocationHandler
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
if (method.getDeclaringClass() == Object.class) {
return method.invoke(invoker, args);
}
if ("toString".equals(methodName) && parameterTypes.length == 0) {
return invoker.toString();
}
if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
return invoker.hashCode();
}
if ("equals".equals(methodName) && parameterTypes.length == 1) {
return invoker.equals(args[0]);
}
// Invoker进行Rpc调用
return invoker.invoke(new RpcInvocation(method, args)).recreate();
}
附录
参照:https://dubbo.gitbooks.io/dubbo-dev-book/implementation.html