一 代理模式
通过代理对象访问目标对象.可以在代理对象中实现额外功能,增强目标对象。
静态代理
动态代理
jdk代理,基于接口生成,使用反射调用目标对象。
cglib代理,使用字节码生成继承子类,覆盖重写目标对象方法。不能代理private和final方法
二 dubbo中代理
dubbo中代理实现为动态代理,分为:基于jdk接口的jdk代理和使用字节码生成方式的javassist代理。
代理类位置2.1ProxyFactory
代理工厂接口2.1.1 <T> T getProxy(Invoker invoker)与<T> T getProxy(Invoker<T> invoker, boolean generic)
在class ReferenceConfig中解析<dubbo:reference/> 引用服务配置时调用,生成目标接口的代理,作为spring管理的单例bean。
参数invoker则表示dubbo架构中的cluster层对象,通过invoker逐层向下调用,最终通过netty channel发送rpc调用消息。
generic则表示是否增加通用接口GenericService的的实现,即由服务端和客户端协商确定接口名称,参数等信息,而不是由dubbo基于接口类解析。
2.1.2 <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url)
在类ServiceConfig中解析<dubbo:service/>配置时调用,封装接口实现类对象proxy,生成统一的Invoker类型的类对象,提供给下层协议层。
netty server层接收到rpc调用消息后,解析获取消息对应的invoker。
2.2 AbstractProxyFactory
仅实现了getProxy接口,处理GenericService和EchoService的接口
EchoService是回声服务,由服务端EchoFilter拦截消息并响应返回传输的接口第一个参数。
2.3 jdk代理
2.3.1 getProxy(Invoker<T> invoker, Class<?>[] interfaces)
public T getProxy(Invoker invoker, Class[] interfaces) {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces,
new InvokerInvocationHandler(invoker));
}
@Override
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]);
}
return invoker.invoke(new RpcInvocation(method, args)).recreate();
}
InvokerInvocationHandler 组装RpcInvocation作为参数调用cluster层invoker.invoke()方法
rpc请求体结构.png
2.3.2 getInvoker(T proxy, Class type, URL url)
public Invoker getInvoker(T proxy, Class type, URL url) {
return new AbstractProxyInvoker(proxy, type, url) {
@Override
protected ObjectdoInvoke(T proxy, String methodName,
Class[] parameterTypes,
Object[] arguments)throws Throwable {
Method method = proxy.getClass().getMethod(methodName, parameterTypes);
return method.invoke(proxy, arguments);
}
};
}
通过反射调用目标服务
2.4 javassist代理
使用字节码方式生成目标接口代理。如下是对应的字节码处理类
字节码处理实现类2.4.1 getProxy(Invoker<T> invoker, Class<?>[] interfaces)
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
getProxy流程图.png
2.4.2 getInvoker(T proxy, Class type, URL url)
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
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);
}
};
}
jdk代理中是通鳄梨是过反射的方式实现方法调用,而这里是使用字节码生成Wrapper类对象,而wrapper.invokeMethod是直接调用目标服务的接口。
getWrapper流程图.png
网友评论