先来一个InvocationHandler示例,InvocationHandler类的作用是:对原始对象的方法做一个拦截。

package com.zhang;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; interface HelloSerivce {
void sayHello();
void sayHi();
} interface FuckService {
void fuck();
} class HelloServiceImpl implements HelloSerivce {
@Override
public void sayHello() {
System.out.println("hello zhang");
} @Override
public void sayHi() {
System.out.println("hi zhang");
}
} public class InvocationHandler_Test {
public static void main(String[] args) {
class MyInvocationHandler implements InvocationHandler {
private Object obj;
public MyInvocationHandler(Object obj) {
this.obj = obj;
} //拦截方法
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("sayHello".equals(method.getName())) {
System.out.println("拦截sayHello");
} else if("sayHi".equals(method.getName())) {
System.out.println("拦截sayHi");
}
//调用原始方法
method.invoke(obj, args);
return null;
} @Override
public String toString() {
return "MyInvocationHandler:" + System.currentTimeMillis();
}
} HelloSerivce helloSerivceImpl = new HelloServiceImpl();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(helloSerivceImpl);
//生成代理
Class<?>[] src = HelloServiceImpl.class.getInterfaces();
Class<?>[] dest = new Class<?>[src.length + 1];
System.arraycopy(src, 0, dest, 0, src.length);
dest[src.length] = FuckService.class; HelloSerivce proxyInstance = (HelloSerivce)Proxy.newProxyInstance(HelloServiceImpl.class.getClassLoader(),
dest, myInvocationHandler);
proxyInstance.sayHello();
proxyInstance.sayHi(); System.out.println(proxyInstance instanceof FuckService);
FuckService fService = (FuckService)proxyInstance;
//报错
fService.fuck();
}
}

dubbo consumer的InvokerInvocationHandler实现了InvocationHandler接口,拦截的是MockClusterInvoker对象的方法,这是jdk动态代理。

public class InvokerInvocationHandler implements InvocationHandler {
private final Invoker<?> invoker;
public InvokerInvocationHandler(Invoker<?> handler){
this.invoker = handler;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
//如果是Object的方法,直接调用原生对象的方法
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]);
}
//剩下的就需要发送请求给provider了
return invoker.invoke(new RpcInvocation(method, args)).recreate();
}
}

比较一下jdk和javassist动态代理:

//JdkProxyFactory
@SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
interfaces, new InvokerInvocationHandler(invoker));
}
//JavassistProxyFactory
@SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}

存在HelloService接口:

public interface HelloService {
String sayHello();
}

Javassist为它动态生成的类代码大致如下:

class com.alibaba.dubbo.common.bytecode.proxy0 implements
com.alibaba.dubbo.rpc.service.EchoService, com.zhang.HelloService {
public <init>(java.lang.reflect.InvocationHandler arg0){
handler=$1;
}
public static java.lang.reflect.Method[] methods;
private java.lang.reflect.InvocationHandler handler; public java.lang.String sayHello(){
Object[] args = new Object[0];
//handler是InvokerInvocationHandler对象
Object ret = handler.invoke(this, methods[0], args);
return (java.lang.String)ret;
}
public java.lang.Object $echo(java.lang.Object arg0){
Object[] args = new Object[1];
args[0] = ($w)$1;
Object ret = handler.invoke(this, methods[1], args);
return (java.lang.Object)ret;
}
}

从上面能看出来:Javassist动态生成的类直接调用InvocationHandler,不是通过代理调用的。

最新文章

  1. Mac上好用软件集锦
  2. healthkit 记录每天用户的运动情况
  3. Java 8 时间日期库的20个使用示例
  4. Android笔记: 在Eclipse环境下使用Genymotion模拟器
  5. 【京东详情页】——原生js爬坑之标签页
  6. 树莓派.系统.修改声音输出通道(auto,hdmi,耳机接口)
  7. 通过WMI获取机器信息
  8. BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树
  9. Python学习笔记-随机数
  10. Redis 学习手册
  11. 【LeetCode】跳跃游戏
  12. hanlp源码解析之中文分词算法详解
  13. 解决下载经过GZip压缩后的网页乱码问题
  14. 安装e(fx)clipse到Eclipse (JavaFX工具)
  15. 安全:CSRF
  16. 《Linux系统编程(第2版)》
  17. Linux服务器配置---ssh配置
  18. AIM Tech Round 3 (Div. 1) (构造,树形dp,费用流,概率dp)
  19. hibernate-注解及配置
  20. 在eclipse中使用Maven3(笔记二)

热门文章

  1. P3498 [POI2010]KOR-Beads
  2. JavaScript 实现全选 / 反选功能
  3. CSS3实现小黄人动画
  4. C# 将 Stream 写入文件
  5. Django框架(五) Django之模板语法
  6. SpringBoot添加自定义消息转换器
  7. POJ 1845 Sumdiv(求因数和 + 逆元)题解
  8. Maven profile 打包分环境加载不同的资源文件
  9. js精度问题
  10. NOI 8785 装箱问题(0-1背包)