手写JDK动态代理

反射动态代理

为了能够更好实现AOP的思想,在Java中有了动态代理概念,与动态代理相对应的就是静态代理,首先看下面的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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的思想,那使用静态代理的方法如下:

``` java
public class WorkerProxy {
public void aopWorker(IWoker doWoker){
System.out.println("before");
doWoker.sayHello("Rz","Mz");
System.out.println("end");
}
}

定义一个WorkProxy的代理类,在执行方法的时候,使用代理类来执行:

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
Worker worker = new Worker();
new WorkerProxy().aopWorker(worker);
```

静态代理很好立即,即是使用组合类的方式来实现代理模式。这种形式的就是过于单一,代理的接口多的时候,就对应会产生很多代理类。

而java的动态代理就是为了解决这个问题,动态代理实现的代码如下:


``` java
//动态代理类
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;
}
}

```

代码调用:

``` java

IWoker proxy = (IWoker) Proxy.newProxyInstance(
IWoker.class.getClassLoader(),
new Class[]{IWoker.class},
new DynaminProxy(worker));
proxy.sayHello();

```

从上面的代码可以看出,动态代理返回来的`proxy`对象很奇怪,通过调试可以看到对应的类型为:


![Proxy对象](/img/assets/62/01.jpg)



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

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

根据上面的推断,`proxy`的对象的代码应该是:

``` java
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();
}
}
}
```

使用代码进行的调用的时候,运行结果一致。在刚刚的代码中,如何实现的这个功能的呢?

``` java
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
    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;}}}");
}

```
**生成的类结果**
``` java
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
15
16
17
18
19
20
21
22
23
24

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**

``` java

Class<?> aClass = classLoader.loadClass("com.rz.frame.dynamicproxy.$Proxy");
Constructor<?> constructor = aClass.getConstructor(obj.getClass());
Object o = constructor.newInstance(obj);
return o;

作者

付威

发布于

2019-07-23

更新于

2020-08-10

许可协议

评论