Java 代理模式
2024-09-13 09:14:17 # javasec # basic

静态代理

首先简单的说下代理模式,代理可以看做是中介,我们在租房子的时候一般都不是直接找房东租房,而是找中介租房,这个场景中房东就是被中介代理的对象,我们在租房的时候中介帮我们完成我们和房东直接租房的流程,包括看房子介绍房子签合同等等

然后再将一下静态代理和动态代理,静态代理就是通过硬编码写的代理流程,这里简单得通过代码了解一下就知道了

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
package proxy;

public class staticproxy {
public static void use(weapon weapon) {
weapon.attack();
}

public static void main(String[] args) {
weapon taidao = new taidao();
System.out.println("代理之前");
use(taidao);
System.out.println("代理之前");
use(new weaponagent(taidao));
}
}

interface weapon { // 代理接口
public void attack();

}

class taidao implements weapon { // 委托类


@Override
public void attack() {
System.out.println("Use taidao attack");
}
}

class weaponagent implements weapon { // 代理类
private weapon target;

public weaponagent(weapon target) {
this.target = target;
}

@Override
public void attack() {
System.out.println("Shift the taidao");
this.target.attack();
}
}

这里的taidao类就可以理解为房东,weaponagent可以理解为中介,然后staticproxy就是我们自己,在代理之前我们是直接通过use调用的taidao对象然后返回一个Use taidao attack

之后我们将这个taidao对象交个weaponagent中介,然后我们调用这个中介weaponagent的use方法,他就执行的是如下代码

帮我们调用了taidao对象的attack方法,以及调用该方法是需要的一切准备操作

这就是动态代理

优点:

  • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
  • 公共的业务由代理来完成 . 实现了业务的分工 ,
  • 公共业务发生扩展时变得更加集中和方便 .

缺点 :

  • 一个真是类对应一个代理角色,代码量翻倍,开发效率降低 .

动态代理

静态代理是一个房东对应一个租客,而动态代理则是一个中介对应多个房东,并且这个房东也就是被代理的对象是一个接口,而不是代理的具体一个对象,代理类是动态生成的,我们传入进去的就只有一个接口

同样也是举个例子看看

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
package proxy;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class dynamicproxy {

public static void main(String[] args) {
tachi tachi = new tachi();
System.out.println("代理之前");
tachi.attack();

System.out.println("代理之后");
ClassLoader classloader = tachi.getClass().getClassLoader();
Class<?>[] interfaces = tachi.getClass().getInterfaces();
InvocationHandler invocation = new swordagent(tachi);

weapon proxy = (weapon) Proxy.newProxyInstance(classloader, interfaces, invocation);
proxy.attack();
}
}

class tachi implements weapon{ // 委托类


public void attack() {
System.out.println("Use taidao attack");
}


}

class swordagent implements InvocationHandler { // 代理类
private Object target;

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

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Shift the tachi");
return method.invoke(target, args);
}
}

这里要介绍几个类

首先是Proxy类,他是用来生成代理对象的类,里面的静态方法newProxyInstance就是用来生成的

1
2
3
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)

该方法接受三个参数

  • loader:代理对象使用的类加载器
  • interfaces:代理对象所实现的接口
  • InvocationHandler:代理对象的调用处理程序,执行代理对象的任意方法的具体实现类

接着是InvocationHandler,他是一个接口,只有一个方法invoke

里面接受三个参数

  • proxy – 调用该方法的代理对象
  • method -所述方法对应于调用代理实例上的接口方法的实例。方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。
  • args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。

这个处理程序可以理解为静态代理的中介,是具体执行具体代理操作的类,我们可以自己手动编写实现这个接口,然后在invoke方法里面编写调用代理对象某方法的逻辑

当然InvocationHandler也就收代理对象,所以InvocationHandler的实现类是执行操作的核心类,而Proxy类是一个用来动态生成代理对象的类

代理应用

动态代理在反序列化中的应用最明显的就是Lazymap的CC1链,AnnotationInvocationHandler这个类的invoke方法里面的代码能够触发恶意方法,而这个invoke方法可以理解为反序列化中的readObject方法,是可以被自动调用的,只是触发条件不同,一个是在对象被反序列化的时候自动调用,一个是对象如果是代理对象时在执行任意方法时自动调用