java反序列化入门篇-03-动态代理

java反序列化入门篇-03-动态代理

在这一篇中想记录一下学习代理的原理和作用,但在基础篇-01中已经用代码有一个大致的了解了,后面尽可能减少重复

java的代理模式

先简单来说一下什么是代理吧,代理的本质是不修改目标类原有代码的前提下,在目标方法执行前后增加额外逻辑(增强)。 有一个代理对象,持有目标对象引用;外部调用者只和代理对象打交道,由代理对象转发请求给真实目标。而在java的代理模式中存在静态代理和动态代理两种代理模式。

静态代理

我们来以租客找中介从房东手里租房为例子来去理解静态代理

想要在java中实现上面的逻辑,我们就需要4个文件,所代表的分别是租客,中介,房东和房源,其中房源应该是接口,其他三个为具体类。

有些师傅可能疑惑为什么房源应该是接口,对于房源来说我们要携带的方法是租房,但具体实现肯定是由房东和中介去实现的,所以房源中只需要放定义即可。虽然使用继承我们看上去也可以实现这种功能,但就不符合我们的编程思维了,继承应该表示子类是父类下的一个小分支,二者根源应该相同,且java使用的是单继承制,从使用和概念上都不太合适。而接口表达的是具备某种能力,我们也可以实现多个接口,更适合我们的利用。

Rent.java

1
2
3
4
public interface Rent {  

public void rent();
}

Host.java

1
2
3
4
5
6
public class Host implements Rent {  

public void rent(){
System.out.println("房东要出租房子");
}
}

Proxy.java

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Proxy {  

private Host host;

public Proxy(){}
public Proxy(Host host){
this.host = host;
}

public void rent(){
host.rent();
}
}

Client.java

1
2
3
4
5
6
7
public class Client {  
public static void main(String[] args) {
Host host = new Host();
Proxy proxy = new Proxy(host);
proxy.rent();
}
}

返回

1
房东要出租房子

在上面的文件中我们Rent.java定义为接口,也就是我们上面的房源;而Host.java,Proxy.java,Client.java分别对应房东,中介和租客。但中介的职责显然不可能和房东完全一样,他还要收中介费呢,谁白干活呢。此时只需要在Proxy.java内修改即可。

改进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
package src.JdkProxy.StaticProxy;  

// 中介
public class Proxy {

private Host host;

public Proxy(){}
public Proxy(Host host){
this.host = host;
}

public void rent(){
host.rent();
contract();
fare();
}

// 看房
public void seeHouse(){
System.out.println("中介带你看房");
}

// 收中介费
public void fare(){
System.out.println("收中介费");
}

// 签租赁合同
public void contract(){
System.out.println("签租赁合同");
}
}

返回

1
2
3
房东要出租房子
签租赁合同
收中介费

优点:

  • 职责清晰,解耦
  • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 。
  • 公共业务拓展时无需修改真实角色,可以集中处理

缺点:

  • 每一个目标类,都要单独手写一个代理类。代码数量庞大。
  • 代理逻辑复用差

那就有人在想了,有没有什么办法可以保留静态代理的优点但又抛弃其缺点,于是动态代理就诞生了

动态代理

我们原本在静态代理中是写死了一个类一个代理,但在动态代理的概念中,我们的代理并不专门为某一个类服务而是动态定义的。那这个时候我们应该代理什么呢,代理的是每个类都要实现的接口,不得不佩服前人的思维。

UserService.java

1
2
3
4
5
6
public interface UserService {  
public void add();
public void delete();
public void update();
public void query();
}

UserServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class UserServiceImpl implements UserService{  
@Override
public void add() {
System.out.println("增加了一个用户");
}

@Override
public void delete() {
System.out.println("删除了一个用户");
}

@Override
public void update() {
System.out.println("更新了一个用户");
}

@Override
public void query() {
System.out.println("查询了一个用户");
}
}

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

public class UserProxyInvocationHandler implements InvocationHandler {

// 被代理的接口
private UserService userService;

public void setUserService(UserService userService) {
this.userService = userService;
}

// 动态生成代理类实例
public Object getProxy(){
Object obj = Proxy.newProxyInstance(this.getClass().getClassLoader(), userService.getClass().getInterfaces(), this);
return obj;
}

// 处理代理类实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method);
Object obj = method.invoke(userService, args);
return obj;
}

//业务自定义需求
public void log(Method method){
System.out.println("[Info] " + method.getName() + "方法被调用");
}
}

Client.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import src.JdkProxy.DynamicProxy.UserServiceImpl;  

public class Client {
public static void main(String[] args) {
// 真实角色
UserServiceImpl userServiceImpl = new UserServiceImpl();
// 代理角色,不存在
UserProxyInvocationHandler userProxyInvocationHandler = new UserProxyInvocationHandler();
userProxyInvocationHandler.setUserService((UserService) userServiceImpl); // 设置要代理的对象

// 动态生成代理类
UserService proxy = (UserService) userProxyInvocationHandler.getProxy();

proxy.add();
proxy.delete();
proxy.update();
proxy.query();
}
}

总结篇中也有通过代码中的动态代理进行讲述,这里就不再详细讲述了

动态代理的意义

有了动态代理,我们就不需要给每一位房东都配备一个中介,而是哪位房东需要中介我们就为哪位房东服务,运行时由 JVM 动态生成代理字节码,内存中创建代理 Class,不需要提前写代理.java文件。大大减少了我们的代码量。同时我们对于真实类的改动频率可以极大被减少,公共方法只需要在代理类进行添加或修改就好。

并且一个代理还可以实现多个接口,动态代理其实远不止眼前这点知识,但我们学反序列化到这足以,讲多容易偏题,后面会单开一篇来写一下。

动态代理在java反序列化中的作用

动态代理最妙的地方就在于invoke 方法在动态代理当中会自动执行。

我们假设一下如果存在一个能够利用漏洞的类B.f,我们将入口类定为A。最为理想的情况是A[O],存在O.f,那么此时我们只需传入B赋值给O,即可调用B.f,当然这只是我们说的最为理想的情况,现实中几乎不可能遇见。

比较可能出现的情况是A[O],存在O.abc。如果O是一个代理类的话,且O的invoke方法中存在.f,那么此时我们就有用武之地了。给大家详细列一下整个调用逻辑

1
2
3
4
A[O] -> O.abc
O[M] invoke -> M.f
---传入B----
O[B] invoke -> B.f

动态代理的出现为反序列化找寻触发链提供了新方案和新思路,让其不必完全拘泥于同名函数的调用,把触发点放在 readObject 或者 invoke 两个位置。且JDK原生代理类大多实现Serialize,对于我们的反序列化研究提供了更多便利。


java反序列化入门篇-03-动态代理
http://blog.yunli1.com/2026/09/25/java反序列化入门篇-03-动态代理/
作者
yunli
发布于
2026年9月25日
许可协议