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