基于Javassist实现JDK的动态代理Proxy
使用
首先复习一下怎么使用动态代理
- 定义一个用户接口
- 实现一个用户接口的实现类
- 实现一个
InvocationHandler
- 使用
Proxy.newProxyInstance
创建一个代理即可使用
public interface SayHelloInterface {
void addMessage(String msg,String from,String to);
String say();
}
public class SayHelloImpl implements SayHelloInterface {
private String msg = null;
@Override
public void addMessage(String msg, String from, String to) {
String message = "实现类添加Message "+msg+"from "+from+" to "+to;
this.msg = message;
System.out.println(message);
}
@Override
public String say() {
System.out.println("实现类执行say函数并返回消息");
return msg;
}
}
public class SayHelloInvocation implements InvocationHandler {
private SayHelloInterface target;
public SayHelloInvocation(SayHelloInterface target) {
this.target = target;
}
public static SayHelloInterface createProxy(SayHelloInterface target){
return (SayHelloInterface) Proxy.newProxyInstance(target.getClass().getClassLoader()
,target.getClass().getInterfaces(),new SayHelloInvocation(target));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理方法前置内容执行");
Object result= method.invoke(target,args);
String txt = result == null ? "null" : result.toString();
System.out.println("代理后置方法内容执行,返回值为"+ txt);
System.out.println("-------------");
return null;
}
}
@Test
public void testJdkProxy(){
SayHelloInterface say = new SayHelloImpl();
SayHelloInterface proxy= SayHelloInvocation.createProxy(say);
proxy.addMessage("message","xiaoming","xiaowang");
proxy.say();
}
原理介绍
JDK的动态代理是如何实现的呢?我们跟踪Proxy的源码,大概总结一下其newProxyInstance
的流程为:
- 记录handler
- 在缓存中找代理类Class,如果没有则创建一个并返回代理类Class
- 拿到代理类的有参构造器,传入
handler
进行newInstance
并返回
我们先忽略缓存,重点看一下创建代理的流程,也就是ProxyGenerator.generateProxyClass
这个方法,太深的源码我们不追,我们看一下它生成的代理文件是什么样的。为了篇幅,将toString()
和hashCode()
方法删去,其实现和equals()
是相同的
public final class proxy extends Proxy implements SayHelloInterface {
private static Method m1;
private static Method m3;
private static Method m4;
public proxy(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void addMessage(String var1, String var2, String var3) throws {
try {
super.h.invoke(this, m3, new Object[]{var1, var2, var3});
} catch (RuntimeException | Error var5) {
throw var5;
} catch (Throwable var6) {
throw new UndeclaredThrowableException(var6);
}
}
public final String say() throws {
try {
return (String)super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("cn.jwb5.proxy.SayHelloInterface").getMethod("addMessage", Class.forName("java.lang.String"), Class.forName("java.lang.String"), Class.forName("java.lang.String"));
m4 = Class.forName("cn.jwb5.proxy.SayHelloInterface").getMethod("say");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
我们可以看到,代理类继承了Proxy
类,并实现了用户接口。在代理类实现的用户接口的方法中,所有操作均委托给了父类handler.invoke()
方法来处理。同时通过反射将target
对象和被方法Method
通过参数传递了过去,使handler.invoke()
能够通过method.invoke(target,args)
调用被代理对象的方法。
在其父类Proxy
中存在一个protected InvocationHandler h
的属性,存着对应的InvocationHandler
对象。Proxy
在拿到代理类后,会通过反射拿到代理类的有参构造器(继承自Proxy
的protected Proxy(InvocationHandler h)
),通过有参构造器传入InvocationHandler
实例化代理对象并返回。
自己实现
了解了动态代理的具体实现,我们接下来借用javassist
来自己写一个简单版的动态代理。这里省略了Object
方法的代理以及异常包围块,仅对用户接口方法实现代理。
定义处理器接口InvocationHandler
public interface InvocationHandler {
Object invoke(Object proxy, Method method,Object[] args);
}
定义Proxy类
这个类的作用是
- 维护代理类的缓存
- 实例化代理类对象并返回
public class Proxy {
protected InvocationHandler handler;
private static Map<String,Class> cache = new ConcurrentHashMap<>();
public static Object newProxy(ClassLoader loader,Class interfaceClass,InvocationHandler h) throws Exception {
Class proxyClass = cache.get(interfaceClass.getName());
if (proxyClass == null){
proxyClass = ProxyGenerator.generateClass(interfaceClass);
cache.putIfAbsent(interfaceClass.getName(),proxyClass);
}
Object instance = proxyClass.newInstance();
Method m = instance.getClass().getMethod("setHandler",InvocationHandler.class);
m.setAccessible(Boolean.TRUE);
m.invoke(instance,h);
return instance;
}
// 这里我使用set的方法注入handler而不是构造器
public void setHandler(InvocationHandler handler) {
this.handler = handler;
}
}
定义ProxyGenerator
这个类的作用是生成代理类并进行加载
public class ProxyGenerator {
private static volatile AtomicInteger count = new AtomicInteger(0);
private static String PRE_FIX = "JWB_Proxy&";
public static Class generateClass(Class interfaceClass) throws NotFoundException, CannotCompileException {
String proxyClassName = interfaceClass.getName()+PRE_FIX+count.getAndIncrement();
// 新建一个代理类,继承Proxy类,并实现给定的接口
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass(proxyClassName);
ctClass.setSuperclass(pool.getCtClass(Proxy.class.getName()));
ctClass.addInterface(pool.getCtClass(interfaceClass.getName()));
// 接口的所有方法
Method[] methods = interfaceClass.getMethods();
// method方法计数器,用于名称生成,生成顺序按照上面methods中的顺序来,生成m0,m1,m2.....
int methodCount = 0;
for (Method m : methods){
String methodName = m.getName();
Class returnType = m.getReturnType();
Parameter[] parameters = m.getParameters();
// 1. 通过反射拿到用户接口的方法引用,这些引用要在调用invoke方法时传递过去,从而让invoke方法能够去调用target的对应方法
StringBuilder fieldBuilder = new StringBuilder();
fieldBuilder.append("private static java.lang.reflect.Method ").append("m").append(methodCount)
.append(" = ").append("Class.forName(").append("\"").append(interfaceClass.getName()).append("\"").append(")").append(".")
.append("getMethod(").append("\"").append(m.getName()).append("\"").append(",");
if (parameters.length == 0){
fieldBuilder.append("null");
}else {
fieldBuilder.append("new Class[]{");
for (Parameter p : parameters){
fieldBuilder.append("Class.forName(").append("\"").append(p.getType().getName()).append("\"").append(")").append(",");
}
fieldBuilder.delete(fieldBuilder.length()-1,fieldBuilder.length());
fieldBuilder.append("}");
}
fieldBuilder.append(");");
//private static java.lang.reflect.Method m0 = Class.forName("cn.jwb5.proxy.SayHelloInterface").getMethod("say",null);
//private static java.lang.reflect.Method m1 = Class.forName("cn.jwb5.proxy.SayHelloInterface").getMethod("addMessage",new Class[]{Class.forName("java.lang.String"),Class.forName("java.lang.String"),Class.forName("java.lang.String")});
String fieldTxt = fieldBuilder.toString();
ctClass.addField(CtField.make(fieldTxt,ctClass));
//实现接口方法,委托给handler.invoke()去实现
// 方法括号内的参数的文本
String methodParamTxt = buildParamTxt(parameters);
// 第三个方法args的构建
StringBuilder argsTxtBuilder = new StringBuilder();
for (int i = 0;i<m.getParameterCount();i++){
argsTxtBuilder.append("arg").append(i).append(",");
}
String argsTxt = argsTxtBuilder.length()>0 ? argsTxtBuilder.delete(argsTxtBuilder.length()-1,argsTxtBuilder.length()).toString() : null;
argsTxt = argsTxt == null ? "null" : "new Object[]{"+argsTxt+"}";
// 有返回值要进行返回并强转,没有不返回
String returnTxt = returnType.getName().equals("void")? " " : " return ("+returnType.getName()+")";
// method
StringBuilder methodTxtBuilder = new StringBuilder();
methodTxtBuilder.append("public ").append(returnType.getName()).append(" ").append(methodName)
.append("(").append(methodParamTxt).append(")").append("{")
.append(returnTxt).append(" super.handler.invoke").append("(")
.append("this").append(",").append("m").append(methodCount).append(",").append(argsTxt).append(");").append("};");
//public java.lang.String say( ){ return (java.lang.String) super.handler.invoke(this,m0,null);};
//public void addMessage(java.lang.String arg0,java.lang.String arg1,java.lang.String arg2){ super.handler.invoke(this,m1,new Object[]{arg0,arg1,arg2});};
ctClass.addMethod(CtMethod.make(methodTxtBuilder.toString(),ctClass));
methodCount++;
}
// 传递handler
String setHandlerTxt = "public void setHandler(cn.jwb5.proxy.InvocationHandler h){super.setHandler(h);};";
ctClass.addMethod(CtMethod.make(setHandlerTxt,ctClass));
return ctClass.toClass();
}
// java.lang.String arg0,java.lang.String arg1
private static String buildParamTxt(Parameter[] parameters){
if (parameters.length == 0) return " ";
StringBuilder builder = new StringBuilder();
int argCount = 0;
for (Parameter p : parameters){
builder.append(p.getType().getName()).append(" ").append("arg").append(argCount++).append(",");
}
return builder.toString().substring(0,builder.length()-1);
}
测试
public interface SayHelloInterface {
void addMessage(String msg,String from,String to);
String say();
}
public class SayHelloImpl implements SayHelloInterface {
private String msg = null;
@Override
public void addMessage(String msg, String from, String to) {
String message = "实现类添加Message "+msg+"from "+from+" to "+to;
this.msg = message;
System.out.println(message);
}
@Override
public String say() {
System.out.println("实现类执行say函数并返回消息");
return msg;
}
}
public class MyInvocationImpl implements InvocationHandler {
private SayHelloInterface target;
public MyInvocationImpl(SayHelloInterface target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
try {
System.out.println("代理方法前置内容执行");
Object result= null;
result = method.invoke(target,args);
String txt = result == null ? "null" : result.toString();
System.out.println("代理后置方法内容执行,返回值为"+ txt);
System.out.println("-------------");
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
@Test
public void test() throws Exception {
SayHelloInterface target = new SayHelloImpl();
SayHelloInterface proxy = (SayHelloInterface) Proxy.newProxy(target.getClass().getClassLoader(),
SayHelloInterface.class,new MyInvocationImpl(target));
proxy.addMessage("message","my","you");
proxy.say();
}
效果
上一篇: Qt中关于C++中的关键字explicit实例讲解
下一篇: powerDisigner使用
推荐阅读
-
深入讲解基于JDK的动态代理机制
-
Java JDK动态代理(AOP)的实现原理与使用详析
-
Java JDK动态代理(AOP)的实现原理与使用详析
-
.NET 下基于动态代理的 AOP 框架实现揭秘
-
实现一个基于动态代理的 AOP
-
jdk动态代理的实现流程(事务处理)
-
动态代理(基于接口)的方式实现线程绑定和事务控制(非aop)
-
Spring AOP 代理实现的两种方式: JDK动态代理 和 Cglib框架动态代理
-
FeignClient原理解析,100行代码实现feign功能,mybatis的mapper、dubbo、feign实现原理模拟。spring扫描自定义注解原理。Javassist实现动态代理原理
-
ArrayList类源码解析——ArrayList动态数组的实现细节(基于JDK8)