JAVA代理模式

Java三种代理模式:静态代理、动态代理和cglib代理 https://segmentfault.com/a/1190000011291179

Java 动态代理详解 https://juejin.cn/post/6844903744954433544#heading-3

静态代理

静态代理帮助我们实现功能增强的效果

我们可以在不入侵代理目标的源代码的情况下扩展他原来的方法

这种代理方式需要代理对象和目标对象实现一样的接口

缺点:

  1. 冗余。由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。
  2. 不易维护。一旦接口增加方法,目标对象与代理对象都要进行修改。

动态代理

考虑到静态代理的缺点,我们如何改进:

让代理类动态生成,就不用去定义过多的代理类。

JDK动态代理

JDK动态代理主要涉及两个类:java.lang.reflect.Proxy 和 java.lang.reflect.InvocationHandler

先编写一个LogHandler来实现InvocationHandler接口

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
package com.jdkDemo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;

public class LogHandler implements InvocationHandler {
//被代理的对象,实际的方法的执行者
Object target;

public LogHandler(Object target){
this.target = target;
}

//实现InvocationHandler接口
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target, args);
after();
return result;
}

public void before(){
System.out.println(String.format("log start time [%s]",new Date()));
}

public void after(){
System.out.println(String.format("log end time [%s]",new Date()));
}
}

然后用java.lang.reflect.Proxy的newProxyInstance方法来构造一个指定接口的代理类的额一个新实例,所有方法会调用给定处理器(也就是LogHandler)的invoke方法

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
package com.jdkDemo;

import com.jtDemo.UserService;
import com.jtDemo.UserServiceImpl;

import java.lang.reflect.Proxy;

public class Client {
public static void main(String[] args) {
//1.创建被代理的对象
UserServiceImpl userServiceimpl = new UserServiceImpl();
//2.获取对应的ClassLoader
ClassLoader classLoader = userServiceimpl.getClass().getClassLoader();
//3.获取所有接口的Class,这里只实现了一个UserService接口
Class<?>[] interfaces = userServiceimpl.getClass().getInterfaces();
//4.创建一个将传给代理类的调用请求处理器,处理所有的代理对象上的方法调用
//这里创建的是一个自定义的日志处理器,须传入实际的执行对象 userServiceImpl
LogHandler handler = new LogHandler(userServiceimpl);
//5.根据上面的信息创建代理对象
/*
在这个过程中,
a.JDK会通过根据传入的参数信息动态地在内存中创建和.class 文件等同的字节码
b.然后根据相应的字节码转换成对应的class,
c.然后调用newInstance()创建代理实例
*/
UserService proxy = (UserService) Proxy.newProxyInstance(classLoader, interfaces, handler);
proxy.select();
proxy.update();
}
}

项目输出:

1
2
3
4
5
6
log start time [Sat Mar 12 09:02:44 CST 2022]
查询方法
log end time [Sat Mar 12 09:02:44 CST 2022]
log start time [Sat Mar 12 09:02:44 CST 2022]
更新方法
log end time [Sat Mar 12 09:02:44 CST 2022]

可以发现传给代理的方法都被转发到了处理器LogHandler handler = new LogHandler(userServiceimpl);中的invoke方法中

我们可以通过工具分析出构造出来的动态代理类:

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
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import proxy.UserService;

public final class UserServiceProxy extends Proxy implements UserService {
private static Method m1;
private static Method m2;
private static Method m4;
private static Method m0;
private static Method m3;

public UserServiceProxy(InvocationHandler var1) throws {
super(var1);
}

public final boolean equals(Object var1) throws {
// 省略...
}

public final String toString() throws {
// 省略...
}

public final void select() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}

public final int hashCode() throws {
// 省略...
}

public final void update() throws {
try {
super.h.invoke(this, m3, (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"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m4 = Class.forName("proxy.UserService").getMethod("select");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m3 = Class.forName("proxy.UserService").getMethod("update");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}

可以看到动态代理类在执行方法的时候都是用handler中我们重写的invoke方法来调用的

  • UserServiceProxy 继承了 Proxy 类,并且实现了被代理的所有接口,以及equals、hashCode、toString等方法
  • 由于 UserServiceProxy 继承了 Proxy 类,所以每个代理类都会关联一个 InvocationHandler 方法调用处理器
  • 类和所有方法都被 public final 修饰,所以代理类只可被使用,不可以再被继承
  • 每个方法都有一个 Method 对象来描述,Method 对象在static静态代码块中创建,以 m + 数字 的格式命名
  • 调用方法的时候通过 super.h.invoke(this, m1, (Object[])null); 调用,其中的 super.h.invoke 实际上是在创建代理的时候传递给 Proxy.newProxyInstance 的 LogHandler 对象,它继承 InvocationHandler 类,负责实际的调用处理逻辑

image.png