Java 代理模式(简单理解回顾)

✅ 一句话定义

代理 = 找一个替身(代理类),帮你控制对真实目标对象的访问;在调用真实方法前后,加额外逻辑,不改原有目标代码。

真实对象:做核心业务 代理对象:增强(日志、耗时、权限、事务),不改动原有业务代码

✅ 为什么会出现代理模式(解决什么痛点)

核心痛点:开闭原则

原有业务代码只负责核心逻辑,不想修改它;但又想在方法执行前后加通用能力(日志、监控、权限校验、事务)。

如果不使用代理: 直接改业务方法,到处写日志代码 → 业务代码和通用杂糅在一起;新增 / 删除日志,要修改所有业务方法,违反开闭原则。

代理思路:通用增强逻辑放到代理里面,业务代码不动。

✅ 3 种代理分类(只抓重点)

1. 静态代理(写死代码,编译期就写好代理类)

特点:代理类代码手动写,一个目标类对应一个代理类 缺点:目标类越多,代理类爆炸,维护麻烦。

示例场景:用户服务,新增打印耗时

java 复制代码
// 接口
public interface UserService {
    void addUser();
}
// 真实类(核心业务)
class UserServiceImpl implements UserService{
    @Override
    public void addUser() {
        System.out.println("新增用户【核心业务】");
    }
}
// 静态代理类
public class UserServiceProxy implements UserService{
    // 持有真实对象
    private UserService target;
    public UserServiceProxy(UserService target){
        this.target = target;
    }
    @Override
    public void addUser() {
        System.out.println("【代理前置】方法开始,记录时间");
        target.addUser(); // 调用真实业务
        System.out.println("【代理后置】方法结束,统计耗时");
    }
}

使用:

java 复制代码
UserService target = new UserServiceImpl();
UserService proxy = new UserServiceProxy(target);
proxy.addUser();

2. JDK 动态代理(⭐Spring AOP 底层之一)

要求:目标对象必须实现接口 运行期动态生成代理类,不用手写代理代码。 原理:java.lang.reflect.Proxy + InvocationHandler 调用代理方法时,进入invoke(),在 invoke 里面执行增强 + 真实方法。

3. CGLIB 代理(⭐Spring AOP 底层之二)

目标类不用实现接口,通过继承目标类生成子类作为代理 不能代理 final 类 /final 方法(无法继承重写)
Spring AOP 规则: 目标有接口 → 默认 JDK 动态代理;无接口 → CGLIB

✅ 日常开发什么时候巧妙用代理(真实场景)

  1. Spring AOP(最常见!本质就是动态代理) 给接口方法统一加:日志、耗时统计、异常捕获、权限校验、事务 @Transactional

事务:方法执行前开启事务,异常回滚,正常提交,全部在代理增强逻辑,业务代码不用管。

  1. RPC 框架:Dubbo 消费端拿到的服务接口,其实是代理对象。调用接口方法时,代理帮你做序列化、网络传输、调用远程服务,本地只是接口,真实逻辑在远端。

  2. Mybatis Mapper 接口 Mapper 只是接口,没有实现类!Mybatis 启动时生成代理对象。调用 mapper.select (),代理帮你拼装 SQL、执行 JDBC、封装结果。👉 这个是面试高频!

  3. 本地缓存、限流、熔断增强 调用目标方法前,代理先判断限流;命中缓存直接返回,不执行真实方法。

✅ 代理 vs 装饰器(容易混淆,一句话区分)

  • 代理:侧重【控制访问】 ,能不能执行、权限、远程调用;代理和目标不一定实现一模一样的目的(Dubbo 代理根本本地没有实现)
  • 装饰器:侧重【增强功能】,包装同一个对象,不断叠加能力;IO 流 BufferedReader 就是装饰器

✅ 核心总结

  1. 目的:不修改原有业务代码,对方法做增强,遵守开闭原则
  2. 静态代理:手写代理类,类多了臃肿;
  3. JDK 代理:需要接口;CGLIB:继承,不需要接口
  4. 项目最常见:SpringAOP、Dubbo 消费端、MyBatis Mapper,底层都是动态代理

📝 速记口诀

代理替身控访问,原有业务不用改; 静态手写类爆炸,动态运行生成快; JDK 代理要接口,CGLIB 继承来覆盖; AOP 事务与 Mybatis,RPC 远程都靠它。

相关推荐
她的男孩1 小时前
Spring Boot 4 升级别只看编译绿:Forge Admin 在 Jackson、Tomcat JSON 限流、MP 包名与 Flowable 库上踩过的坑
java·spring boot·后端
Knight_AL1 小时前
别把 ThreadLocal 写进 Jackson Serializer
java·spring boot·spring
Song_RsHt1 小时前
Gateway (上):路由与转发,微服务的统一入口
java·笔记·后端·学习·gateway
invicinble1 小时前
对服务器资源的理解--理解用户请求,部署,服务器资源相关的映射层
开发语言
漫步人生走在路上1 小时前
用小语种SEO突破外贸B2B天花板:法语、德语市场的实测数据
开发语言·前端·javascript·人工智能·搜索引擎·ecmascript
paopaokaka_luck1 小时前
校园新闻推荐系统(DeepSeek新闻助手、个性化推荐算法、 Redis热词排行榜、ECharts运营分析、互动与实时通知、新闻运营闭环)
java·spring boot·mysql·spring·tomcat·echarts·intellij idea
yuniko-n1 小时前
【JUC】线程池
java·开发语言
小天源2 小时前
智叟云集政策监测技术方案——原文解析、证据提取与可核验摘要
java·服务器·数据库
dwm888888882 小时前
c# 创建使用本地NuGet包
开发语言·c#