反射动态代理
为了能够更好实现AOP的思想,在Java中有了动态代理概念,与动态代理相对应的就是静态代理,首先看下面的代码。
1 2 3 4 5 6 7 8 9 10 11
| public interface IWoker { String sayHello(String name,String code) ; }
public class Worker implements IWoker{ @Override public String sayHello(String name,String code) { System.out.println("hello"); } }
|
如果我们想在sayHello
的方法前后分别都打印一条日志,实现AOP的思想,那使用静态代理的方法如下:
1 2 3 4 5 6 7
| public class WorkerProxy { public void aopWorker(IWoker doWoker){ System.out.println("before"); doWoker.sayHello("Rz","Mz"); System.out.println("end"); } }
|
定义一个WorkProxy
的代理类,在执行方法的时候,使用代理类来执行:
1 2
| Worker worker = new Worker(); new WorkerProxy().aopWorker(worker);
|
静态代理很好立即,即是使用组合类的方式来实现代理模式。这种形式的就是过于单一,代理的接口多的时候,就对应会产生很多代理类。
而java的动态代理就是为了解决这个问题,动态代理实现的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class DynaminProxy implements InvocationHandler { private Object subject; public DynaminProxy(Object subject) { this.subject = subject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before"); Object obj = method.invoke(subject, args); System.out.println("end"); return obj; } }
|
代码调用:
1 2 3 4 5 6 7
| IWoker proxy = (IWoker) Proxy.newProxyInstance( IWoker.class.getClassLoader(), new Class[]{IWoker.class}, new DynaminProxy(worker)); proxy.sayHello();
|
从上面的代码可以看出,动态代理返回来的proxy
对象很奇怪,通过调试可以看到对应的类型为:
对于Proxy
对象可以通过java语法分析如下:
Proxy
对象的类一定是实现了IWorker
接口
- 执行方法的时候,是通过调用
DynaminProxy
中invoke
方法来调用真正的方法
根据上面的推断,proxy
的对象的代码应该是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class $Proxy implements IWoker { private DynaminProxy h; public $Proxy(DynaminProxy dynaminProxy) { this.h = dynaminProxy; } @Override public String sayHello(String name,String code) { try { Method m = IWoker.class.getDeclaredMethod("sayHello", name.getClass(),code.getClass); Object invoke = this.h.invoke(null, m, new Object[]{name,code}); } catch (Throwable ex) { ex.printStackTrace(); } } }
|
使用代码进行的调用的时候,运行结果一致。在刚刚的代码中,如何实现的这个功能的呢?
1
| Proxy.newProxyInstance(IWoker.class.getClassLoader(), new Class[]{IWoker.class}, new DynaminProxy(worker));
|
再观察动态代理的创建方式,有三个参数ClassLoader
,Class的数组
和最终的是执行的代码。
根据上面的代码,可以先确定代码实现的思路:
- 动态创建动态代理类
$Proxy.java
- 编译成
$Proxy.class
- 使用
ClassLoader
加载对应的类,创建对象返回。
根据上面的思路,可以编写代码如下:
创建$Proxy.java类,实现动态生成类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| StringBuilder classContent = new StringBuilder(); classContent.append("package com.rz.frame.dynamicproxy;"); Class targetInfo = clazz[0]; String targetInfoName = targetInfo.getSimpleName(); String dynamicName = obj.getClass().getSimpleName(); classContent.append(" import ").append(targetInfo.getName()).append(";"); classContent.append("import java.lang.reflect.Method;"); classContent.append("public class $Proxy implements ").append(targetInfoName); classContent.append("{private ").append(dynamicName).append(" target;"); classContent.append("public $Proxy(").append(dynamicName).append(" target){this.target=target;}"); Method[] declaredMethods = targetInfo.getDeclaredMethods(); for (Method m : declaredMethods) { String methodName = m.getName(); Class returnTYpe = m.getReturnType(); Class<?>[] parameterTypes = m.getParameterTypes(); StringBuilder argContent = new StringBuilder(); StringBuilder argsName = new StringBuilder(); StringBuilder argsClass = new StringBuilder(); int i = 0; for (Class param : parameterTypes) { String sName = param.getSimpleName(); argContent.append(sName).append(" var").append(i).append(","); argsName.append(" var").append(i).append(","); argsClass.append(" var").append(i).append(".getClass(),");
i++; } if (argContent.length() > 0) { argContent = new StringBuilder(argContent.substring(0, argContent.lastIndexOf(","))); argsName = new StringBuilder(argsName.substring(0, argsName.lastIndexOf(","))); argsClass = new StringBuilder(argsClass.substring(0, argsClass.lastIndexOf(","))); } classContent.append("public ").append(returnTYpe.getSimpleName()).append(" ").append(methodName).append("(").append(argContent).append("){"); classContent.append(" try{Method m =").append(targetInfoName).append(".class.getDeclaredMethod(\"").append(methodName).append("\",").append(argsClass).append(");");
classContent.append(" Object invoke = this.target.invoke(").append("this,m,new Object[]{ ").append(argsName).append("});"); classContent.append("return (").append(returnTYpe.getSimpleName()).append(")invoke;} catch (Throwable ex) {return null;}}}"); }
|
生成的类结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com.rz.frame.dynamicproxy;
import com.rz.frame.dynamicproxy.IWoker;
import java.lang.reflect.Method;
public class $Proxy implements IWoker { private DynaminProxy target;
public $Proxy(DynaminProxy target) { this.target = target; }
public String sayHello(String var0, String var1) { try { Method m = IWoker.class.getDeclaredMethod("sayHello", var0.getClass(), var1.getClass()); Object invoke = this.target.invoke(this, m, new Object[]{var0, var1}); return (String) invoke; } catch (Throwable ex) { return null; } } }
|
把类写入文件,调用编译器编译成.class文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| File file = new File(this.getClass().getResource("").getPath().concat("$Proxy.java")); FileWriter fw = new FileWriter(file); fw.write(classContent.toString()); fw.flush(); fw.close();
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileManager = javaCompiler.getStandardFileManager(null, null, null); Iterable unit = fileManager.getJavaFileObjects(file); JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileManager, null, null, null, unit); task.call(); fileManager.close();
|
使用classloader加载class
1 2 3 4 5 6
| Class<?> aClass = classLoader.loadClass("com.rz.frame.dynamicproxy.$Proxy"); Constructor<?> constructor = aClass.getConstructor(obj.getClass()); Object o = constructor.newInstance(obj); return o;
|