文章目录
- 0.个人感悟
- [1. 概念](#1. 概念)
- [2. 适配场景](#2. 适配场景)
-
- [2.1 适合的场景](#2.1 适合的场景)
- [2.2 常见场景举例](#2.2 常见场景举例)
- [3. 实现方法](#3. 实现方法)
-
- [3.1 静态代理](#3.1 静态代理)
-
- [3.1.1 实现思路](#3.1.1 实现思路)
- [3.1.2 UML类图](#3.1.2 UML类图)
- [3.1.3 代码示例](#3.1.3 代码示例)
- [3.2 动态代理-JDK代理](#3.2 动态代理-JDK代理)
-
- [3.2.1 实现思路](#3.2.1 实现思路)
- [3.2.2 UML类图](#3.2.2 UML类图)
- [3.2.3 代码示例](#3.2.3 代码示例)
- [3.3 动态代理-CGLIB代理](#3.3 动态代理-CGLIB代理)
-
- [3.3.1 实现思路](#3.3.1 实现思路)
- [3.3.2 UML类图](#3.3.2 UML类图)
- [3.3.3 代码示例](#3.3.3 代码示例)
- [4. 优缺点](#4. 优缺点)
-
- [4.1 优点](#4.1 优点)
- [4.2 缺点](#4.2 缺点)
0.个人感悟
- 说起代理模式,很容易想到现实生活中的中介。在客户和实际提供者之间增加了一层,最终还是完成了客户和提供者的交易,但可以做一些额外的动作,比如做服务(收费)等
- 代理是实现方式有很多种,可以逐层演进来理解
- 静态代理,自己去写代码实现,持有代理对象,在方法内做自己的额外动作,大家都能想到的方式
- jdk对于这种场景进行了优化,提供了API,把通用模版提供好,提供了扩展类,我们自己填充业务代码就行,这里也体现了封装、多态的魅力。jdk代理在运行时内存中创建代理对象,不用像静态代理那样提前写代码;不过需要实现接口
- Code Generation Library)是个功能强大、高性能、开源的代码生成库,代理是其中一个功能。对动态代理进一步进行扩展,它也是把通用模版准备好,听过API,我们只用实现自己的特异代码就行。不需要实现接口,也被称为子类代理。
- 实际工作中多用spring aop,这个计划后面会专门整理spring学习笔记系列
- 代理模式的uml图和装饰器模式有些像,但有本质区别:代 理控制访问,装饰器是增强功能
1. 概念
英文定义 (《设计模式:可复用面向对象软件的基础》)
Provide a surrogate or placeholder for another object to control access to it.
中文翻译
为其他对象提供一种代理以控制对这个对象的访问。
理解
- 代理模式是一种结构型设计模式,通过引入代理对象来控制对原始对象的访问
- 代理对象在客户端和目标对象之间 起到中介作用,可以在不修改目标对象的情况下增加额外功能
2. 适配场景
2.1 适合的场景
- 远程访问:为远程对象提供本地代理(RPC、Web Service)
- 延迟加载:创建开销大的对象时,使用虚拟代理延迟实例化
- 访问控制:保护代理控制对敏感对象的访问权限
- 智能引用:在对象被访问时执行额外操作(计数、日志、缓存)
- 缓存代理:为频繁访问的结果提供缓存,提高性能
- 防火墙代理:保护网络资源,控制外部访问
2.2 常见场景举例
- 图片加载:虚拟代理延迟加载大图片,先显示缩略图
- 数据库连接池:连接代理管理连接的生命周期
- Spring AOP:动态代理实现面向切面编程
- VPN:网络访问的代理服务器
- RMI(远程方法调用):Java的远程对象代理
- MyBatis的Mapper接口:通过动态代理实现SQL映射
3. 实现方法
3.1 静态代理
3.1.1 实现思路
- 定义抽象主题接口:声明真实主题和代理的共同接口
- 实现真实主题类:定义实际执行业务逻辑的对象
- 创建代理类:实现主题接口,持有真实主题的引用,并添加额外功能
- 客户端通过代理访问:客户端调用代理对象的方法,代理再调用真实对象
3.1.2 UML类图

角色说明:
- Subject(抽象主题):定义真实主题和代理的共同接口
- RealSubject(真实主题):实际执行业务逻辑的对象
- Proxy(代理):持有真实主题的引用,控制对真实主题的访问
- Client(客户端) :通过代理对象访问真实主题
注意: - 代理和装饰者模式的区别:代理控制访问,装饰者增强功能
3.1.3 代码示例
suject接口和实现
java
public interface ISubject {
/**
* @description 行为方法
* @author bigHao
* @date 2026/1/17
**/
void doAction();
/**
* @description 行为方法2
* @author bigHao
* @date 2026/1/17
**/
void doAction2();
}
public class RealSubject implements ISubject {
@Override
public void doAction() {
System.out.println("do action");
}
@Override
public void doAction2() {
System.out.println("do acton2");
}
}
静态代理
java
public class SubjectProxy implements ISubject {
private ISubject subject;
public SubjectProxy() {
subject = new RealSubject();
}
@Override
public void doAction() {
// 代理行为
System.out.println("proxy acton start");
subject.doAction();
// 代理行为
System.out.println("proxy acton end");
}
@Override
public void doAction2() {
// 代理行为
System.out.println("proxy acton start");
subject.doAction2();
// 代理行为
System.out.println("proxy acton end");
}
}
测试:
java
public class Client {
static void main() {
ISubject proxy = new SubjectProxy();
System.out.println("=== proxy acton1 ===");
proxy.doAction();
System.out.println("=== proxy acton2 ===");
proxy.doAction2();
}
}
输出:
=== proxy acton1 ===
proxy acton start
do action
proxy acton end
=== proxy acton2 ===
proxy acton start
do acton2
proxy acton end
3.2 动态代理-JDK代理
3.2.1 实现思路
- 定义接口:与静态代理相同,需要抽象主题接口
- 实现真实主题:实现业务逻辑的真实类
- 实现InvocationHandler:编写调用处理器,定义代理的增强逻辑
- 使用Proxy.newProxyInstance创建代理:运行时动态生成代理类
- 客户端通过动态代理访问:客户端使用代理对象执行方法
3.2.2 UML类图

3.2.3 代码示例
java.lang.reflect提供了核心API,方法和参数说明:
java
/**
* Proxy类提供用于创建动态代理类和实例的静态方法。
* 它是所有由Proxy创建的动态代理类的父类。
*/
public class Proxy implements java.io.Serializable {
/**
*
* @param loade 定义代理类的类加载器。通常使用目标接口的类加载器,
* 或者使用当前线程的上下文类加载器(Thread.currentThread().getContextClassLoader())
*
* @param interfaces 代理类要实现的接口列表
*
* @param h 调用处理器,当代理实例的方法被调用时,调用处理器的invoke方法会被调用
*
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
}
java
/**
* InvocationHandler是由代理实例的调用处理器实现的接口。
*/
public interface InvocationHandler {
/**
* 处理代理实例上的方法调用并返回结果。
* 当在与之关联的代理实例上调用方法时,将在调用处理器上调用此方法。
*
* @param proxy 调用该方法的代理实例。
* 这是代理对象本身,不是真实的目标对象。
*
* @param method 对应于在代理实例上调用的接口方法的Method实例。
* Method对象的声明类将是在该方法声明的接口,
* 该接口可能是代理类继承该方法的代理接口的超接口。
*
* @param args 包含在代理实例的方法调用中传递的参数值的对象数组。
*
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}、
suject接口和实现
java
public interface ISubject {
/**
* @description 行为方法
* @author bigHao
* @date 2026/1/17
**/
void doAction();
/**
* @description 行为方法2
* @author bigHao
* @date 2026/1/17
**/
void doAction2();
}
public class RealSubject implements ISubject {
@Override
public void doAction() {
System.out.println("do action");
}
@Override
public void doAction2() {
System.out.println("do acton2");
}
}
动态代理
java
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxyName: " + proxy.getClass().getName());
System.out.println("methodName: " + method.getName());
// 代理行为
System.out.println("jdk proxy acton start");
// 反射调用目标对象方法
Object invoke = method.invoke(target, args);
// 代理行为
System.out.println("jdk proxy acton end");
return invoke;
}
});
}
}
测试:
java
public class Client {
static void main() {
ISubject proxyInstance = (ISubject) new ProxyFactory(new RealSubject()).getProxyInstance();
System.out.println("=== jdk proxy acton1 ===");
proxyInstance.doAction();
System.out.println("=== jdk proxy acton2 ===");
proxyInstance.doAction2();
}
}
输出;
java
=== jdk proxy acton1 ===
proxyName: jdk.proxy1.$Proxy0
methodName: doAction
jdk proxy acton start
do action
jdk proxy acton end
=== jdk proxy acton2 ===
proxyName: jdk.proxy1.$Proxy0
methodName: doAction2
jdk proxy acton start
do acton2
jdk proxy acton end
3.3 动态代理-CGLIB代理
3.3.1 实现思路
- 无需接口:CGLIB可以代理没有接口的类
- 创建MethodInterceptor:实现方法拦截器,定义增强逻辑
- 使用Enhancer创建代理:配置Enhancer生成代理类
- 生成子类代理:CGLIB通过生成目标类的子类来实现代理
- 客户端通过CGLIB代理访问:与JDK代理使用方式类似
3.3.2 UML类图

3.3.3 代码示例
Cglib(Code Generation Library)是个功能强大、高性能、开源的代码生成包,被广泛使用,比如spring等
它可以为没有实现接口 的类提供代理
这里示例是用的spring集成的org.springframework.cglib.proxy。
核心API是包下面的Enhancer、MethodInterceptor,感兴趣可以跟一下源码
需要代理的类(不需要实现接口)
java
public class RealSubject {
public void doAction() {
System.out.println("do action");
}
public void doAction2() {
System.out.println("do acton2");
}
}
代理类
java
public class ProxyFactory implements MethodInterceptor {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance() {
// 1.使用api
Enhancer enhancer = new Enhancer();
// 2.设置父类
enhancer.setSuperclass(target.getClass());
// 3.设置回调函数
enhancer.setCallback(this);
// 4.创建代理对象
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("proxyName: " + proxy.getClass().getName());
System.out.println("methodName: " + method.getName());
// 代理行为
System.out.println("cglib proxy acton start");
// 反射调用目标对象方法
Object invoke = method.invoke(target, args);
// 代理行为
System.out.println("cglib proxy acton end");
return invoke;
}
}
测试
java
public class Client {
public static void main(String[] args) {
RealSubject subject = (RealSubject) new ProxyFactory(new RealSubject()).getProxyInstance();
System.out.println("=== cglib acton1 ===");
subject.doAction();
System.out.println("=== cglib acton2 ===");
subject.doAction2();
}
}
输出
=== cglib acton1 ===
proxyName: org.springframework.cglib.proxy.MethodProxy
methodName: doAction
cglib proxy acton start
do action
cglib proxy acton end
=== cglib acton2 ===
proxyName: org.springframework.cglib.proxy.MethodProxy
methodName: doAction2
cglib proxy acton start
do acton2
cglib proxy acton end
4. 优缺点
4.1 优点
高内聚低耦合:
- 代理对象将附加功能与核心业务逻辑分离
- 真实对象只需关注核心功能,代理对象处理访问控制、日志等
提高扩展性: - 符合开闭原则:可以方便地添加新的代理功能而不修改真实对象
- 可以动态地添加或移除代理层
增强安全性: - 保护代理可以控制对敏感对象的访问权限
- 可以隐藏真实对象的复杂性和实现细节
提高性能: - 虚拟代理实现延迟加载,减少系统启动时间和内存占用
- 缓存代理避免重复计算,提高响应速度
提高复用性: - 代理逻辑可以被多个真实对象复用
- 动态代理可以通用地处理一类对象的代理需求
增强可维护性: - 代理模式将横切关注点(日志、事务、安全)集中管理
- 便于实现AOP(面向切面编程)
4.2 缺点
增加系统复杂度:
- 引入额外的代理层,增加了系统的复杂性
- 静态代理需要为每个真实类创建对应的代理类
可能降低性能: - 代理调用增加了一层间接层,可能带来轻微的性能开销
- 动态代理基于反射,性能低于直接调用
代码可读性降低: - 调试时堆栈跟踪更复杂,增加了调试难度
- 代理模式可能使代码流程不够直观
实现复杂性: - 动态代理涉及反射和字节码操作,实现较复杂
- CGLIB代理需要处理final方法、构造函数等特殊情况
可能的循环调用: - 如果代理不当,可能导致无限递归调用
- 需要正确处理代理链的调用顺序
参考: