JDK静态&&动态代理
JDK静态&&动态代理
代理
类里面的类
eg:房东只有房;中介即收中介费,还管理后期的维修问题(不能把所有东西都堆给房东)
静态代理
包含三个角色:
接口类(抽象角色):定义共同的方法(比如 IUser)
目标类(真实角色):实现接口中的方法(比如 UserImpl)
代理类(代理角色):也实现接口,但在调用目标类方法前后加上“增强逻辑”(比如 UserProxy)
示例
接口类:
1
2
3
4
5
6
7
package com.test;
public interface IUser {
public void show();
public void creat();
public void update();
}真实类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.test;
public class UserImpl implements IUser {
@Override
public void show() {
System.out.println("展示");
}
@Override
public void creat() {
System.out.println("creat");
}
@Override
public void update() {
System.out.println("update");
}
}代理类:
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
package com.test;
public class UserProxy implements IUser {
IUser user;
public UserProxy(IUser user) {
this.user = user;
}
@Override
public void show() {
user.show();
System.out.println("调用了show");
}
@Override
public void creat() {
user.creat();
System.out.println("调用了Creat");
}
@Override
public void update() {
user.update();
System.out.println("调用了Update");
}
}执行:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.test;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
//直接连接调用
IUser user = new UserImpl();//接口类引用指向实现类对象
// user.show();
//静态代理
IUser userProxy = new UserProxy(user);//传进真正的对象
userProxy.show();
userProxy.creat();
}
}动态代理
示例
1
2
3
4
5
6
7
8//动态代理 //要代理的接口、要做的事情、classloader InvocationHandler userinvocationhandler = new UserInvocationHandler(user); IUser userProxy = (IUser) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), userinvocationhandler); userProxy.update(); }Proxy.newProxyInstance()就是要新建一个动态代理类
查看传参
代理接口、要传入的东西、类加载器
classloader
第一个是classloader,第二个是类的接口,第三个是调用处理器(传入的东西)
前两个是系统固定给的参数,只有InvocationHandler类得自己写
InvocationHandler类:
1
2
3public class UserInvocationHandler implements InvocationHandler { }
爆红原因:

需要重写invoke
因为:
- JDK 动态代理的所有方法调用,本质上全部都被转发到
InvocationHandler.invoke() - 如果你不重写
invoke(),代理对象调用方法时:- 没有任何逻辑可执行
- 也无法调用真实对象
- 相当于“没有代理”
- InvocationHandler是接口,不是父类,所以接口里面的方法需要实现,也就是通过invoke来实现
重写之后:
最重要的就是
method
不管外界传入什么,都要通过invoke来调用method方法
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class UserInvocationHandler implements InvocationHandler { IUser user; public UserInvocationHandler() { } public UserInvocationHandler(IUser user) { this.user = user; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("调用了"+method.getName()); method.invoke(user, args); return null; } }通过动态调用,来将
真实文件中的接口实现调用不用写上面那么多的静态代码(
UserProxy),节约了代码- JDK 动态代理的所有方法调用,本质上全部都被转发到
流程:
B.f(最终目的)
A[O] ->O .abc
O[O2]invoke->O2.f(使用B.f替换O2)———–>O[B]invoke->B.f
所以A[O] ——->O .abc ———>B.f
总结
代理 一种设计模式不修改原有类 增加功能意义:
少修改代码 适配强在反序列化漏洞中的作用:
readObject>反序列化自动执行
invoke>有函数调用拼接两条链(任意->固定)
对比
| 类型 | 本质 | 代码谁来写? | 可代理方法数量 | 是否需要接口 |
|---|---|---|---|---|
| 静态代理 | 提前写死的代理类 | 你写代理类 | 固定(写几个代理几个) | 要求接口或继承 |
| 动态代理 | JVM 运行时生成代理类 | JVM 自动生成 | 无限制,自动代理全部方法 | JDK 要有接口(CGLIB 可无接口) |
拓展
动态代理的核心思想,就是从“静态代理设计模式”演化出来的。它现在的意义主要是用于教学,帮助理解动态代理的核心思想
现代开发里,静态代理几乎被动态代理和 AOP 完全取代了
AOP
AOP(面向切面编程)就是:给方法“加功能”,但不修改原有代码
1
2
3
4
5
6
7
8
9
10
11
比如:在某个方法(打日志)执行前后自动,但是 不想修改这个方法的源码
AOP 就负责:
👉 把这些“横切功能”自动插入到方法的执行过程前/后/周
就像吃饭的正常流程:点菜 → 做菜 → 上菜 → 吃饭
但是老板偷偷加了一些功能:
每次点菜前:欢迎语(before)
做菜后:卫生检查(after)
饭店厨师没有改自己的代码这些行为是系统自动加的。AOP 技术是基于动态代理实现(动态代理就是 AOP 的底层)
Spring AOP 本质上就是:
1
2
3
4
5
6
7
代理对象(Proxy) → “拦截” → 调用真实对象
在 invoke() 里加:
- before
- after
- around
- afterThrowing所以 AOP = 动态代理的“封装版”、“高级版”。