手写JDK动态代理

反射动态代理

为了能够更好实现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对象

对于Proxy对象可以通过java语法分析如下:

  1. Proxy对象的类一定是实现了IWorker接口
  2. 执行方法的时候,是通过调用DynaminProxyinvoke方法来调用真正的方法

根据上面的推断,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的数组和最终的是执行的代码。

根据上面的代码,可以先确定代码实现的思路:

  1. 动态创建动态代理类$Proxy.java
  2. 编译成$Proxy.class
  3. 使用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;