上一篇文章仔细的分析了 ,由 refer
方法 获取的 代理对象的过程,以及最后获取到的代理对象的结构,但是结尾比较草,本节仔细分析 字节码生成的代理对象。
结构
上一篇文章结尾草草的给出了 代理对象的结构图,但是并没有对(T) PROXY_FACTORY.getProxy(invoker)
进行 整体上的分析:
首先在 Dubbo 的 ProxyFactory中,有两个字节码工具类,一个是JdkProxyFatory
,另一个是 JavassistProxyFactory
。
具体SPI 文件如下:
stub=org.apache.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper
jdk=org.apache.dubbo.rpc.proxy.jdk.JdkProxyFactory
javassist=org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory
并且默认使用的是 JavassistProxyFactory
作为字节码工具。
StubProxyFactoryWrapper
则主要是要执行优先于 ProxyFactory
的一些逻辑,这里主要是在 getProxy
对 配置了 stub
和 local
属性 进行一些额外处理。
在 JavassistProxyFactory中的构造方法如下:
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
上面构造方法主要是使用字节码工具,将多个 interfaces对象(包括了 EchoService)生成一个代理对象,再使用 InvokerInvocationHandler
包装起来。
ProxyFactory$Adaptive 源码
通过一定方式,获取到了 ProxyFactory$Adaptive
源码,便于我们后面分析:
package org.apache.dubbo.rpc;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class ProxyFactory$Adaptive implements org.apache.dubbo.rpc.ProxyFactory {
public org.apache.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, org.apache.dubbo.common.URL arg2) throws org.apache.dubbo.rpc.RpcException {
if (arg2 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg2;
String extName = url.getParameter("proxy", "javassist");
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
return extension.getInvoker(arg0, arg1, arg2);
}
public java.lang.Object getProxy(org.apache.dubbo.rpc.Invoker arg0, boolean arg1) throws org.apache.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
org.apache.dubbo.common.URL url = arg0.getUrl();
String extName = url.getParameter("proxy", "javassist");
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
return extension.getProxy(arg0, arg1);
}
public java.lang.Object getProxy(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
org.apache.dubbo.common.URL url = arg0.getUrl();
String extName = url.getParameter("proxy", "javassist");
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
return extension.getProxy(arg0);
}
}
PROXY_FACTORY.getProxy(invoker) 详解
AbstractProxyFactory 代码示例:
@Override
public <T> T getProxy(Invoker<T> invoker) throws RpcException {
// 不是泛化调用
return getProxy(invoker, false);
}
@Override
public <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException {
Class<?>[] interfaces = null;
String config = invoker.getUrl().getParameter(INTERFACES);
if (config != null && config.length() > 0) {
String[] types = COMMA_SPLIT_PATTERN.split(config);
if (types != null && types.length > 0) {
interfaces = new Class<?>[types.length + 2];
interfaces[0] = invoker.getInterface();
interfaces[1] = EchoService.class;
for (int i = 0; i < types.length; i++) {
// TODO can we load successfully for a different classloader?.
interfaces[i + 2] = ReflectUtils.forName(types[i]);
}
}
}
if (interfaces == null) {
// 加入EchoService.class
interfaces = new Class<?>[]{invoker.getInterface(), EchoService.class};
}
if (!GenericService.class.isAssignableFrom(invoker.getInterface()) && generic) {
// 加入GenericService.class
int len = interfaces.length;
Class<?>[] temp = interfaces;
interfaces = new Class<?>[len + 1];
System.arraycopy(temp, 0, interfaces, 0, len);
interfaces[len] = com.alibaba.dubbo.rpc.service.GenericService.class;
}
return getProxy(invoker, interfaces);
}
以下将一步一步,钻进getProxy 看其具体实现:
- 由
ProxyFactory$Adaptive
,会先检查参数。 - 通过
proxy
参数获取使用的代理工厂,没有则使用默认的javassist
,使用ExtensionLoader
的 SPI 方式获取。 - 在
Adaptive
类中,获取的extension
为 使用StubProxyFactoryWrapper
包装后的ProxyFactory
,所以会先执行StubProxyFactoryWrapper
的getProxy
方法,而是否会执行 具体ProxyFactory
的getProxy
方法,则需要看Wrapper
类的逻辑。
- 进入
StubProxyFactoryWrapper
的getProxy
,最终会先调用AbstractProxyFactory
,这里面的getProxy
方法主要是判断是否需要往代理生成类中再加入GenericService
用于泛化调用。 - 而后调用子类的
getProxy
,这里使用JavassistProxyFactory
为例:
@Override
@SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
- 使用字节码工具,将传入的interfaces类,以及 参数
InvokerInvocationHandler
,动态生成一个新的代理类并返回。
这里为什么是多个呢?在使用Dubbo 的EchoService 及 泛化调用时,都是使用强转的形式,所以这里就传入多个interfaces,才保证了强转不会出错。 - 在使用 javassist 构造
Proxy.getProxy
时候,截取了字节码class 反编译后的 java 代码,可以便于理解
在具体的JavassistProxyFactory
的public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces)
依次会生成两个类:一个是Proxy0
的包装类,另一个是proxy0
,即具体功能存放类。
proxy0 代理类
public class proxy0 implements DC, EchoService, HelloService {
public static Method[] methods;
private InvocationHandler handler;
public String hello(String var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[0], var2);
return (String)var3;
}
public Object $echo(Object var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[1], var2);
return (Object)var3;
}
public proxy0() {
}
public proxy0(InvocationHandler var1) {
this.handler = var1;
}
}
Proxy0 代理类
public class Proxy0 extends Proxy implements DC {
public Object newInstance(InvocationHandler var1) {
return new proxy0(var1);
}
public Proxy0() {
}
}
分析在 JavassistProxyFactory
中的 以下方法:
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
从上面代码中可以有以下收获:
Proxy.getProxy(interfaces)
返回的是一个Proxy0
对象,注意是大写的P- 最后调用
Proxy0
的newInstance
方法,实例化一个包装类型的proxy0
,注意是小写的 - dubbo 里面的
EchoService
或者 泛化调用,都是通过javassist
字节码工具,以实现方法形式实现,所以才可以在业务层面强转成功。 - 对于返回的代理类,也实现对应 refer 的接口,例如上述实现的
HelloService
。 - DC 是dynamic code 缩写,只是一个标识,说明是动态生成的类。
- 对于手动执行方法,都是调用
InvokerInvocationHandler
的invoke
方法
而对于 InvokerInvocationHandler
中invoker 及后面调用逻辑,且看下一篇文章分析。
觉得博主写的有用,不妨关注博主公众号: 六点A君。
哈哈哈,Dubbo小吃街不迷路: