设计模式之代理模式

设计模式之代理模式

在 Java 开发的进阶之路中,设计模式是区分初级程序员与架构师的核心分水岭,而代理模式作为结构型设计模式中最经典、应用最广泛的模式之一,是 Spring AOP、Mybatis、Dubbo、RPC 框架等主流技术的底层核心原理。

对于新手而言,代理模式看似抽象晦涩,但本质上和我们生活中的中介、代购、经纪人、律师完全一致;对于架构师而言,代理模式是实现无侵入式功能增强、权限控制、远程调用、懒加载的终极方案,同时完美契合软件工程的七大设计原则。

本文将由浅入深、通俗易懂地拆解代理模式,从生活案例到代码实战,从静态代理到动态代理(JDK/CGLIB),从设计原则结合到框架源码分析,全方位覆盖代理模式的所有知识点,帮助你彻底掌握这一核心设计模式。


第一部分:代理模式基础认知(由浅入深第一步)

1.1 生活中的代理:秒懂核心逻辑

在正式讲解技术概念前,我们先看 3 个生活中最常见的代理场景,你会发现代理的本质从未改变

  1. 租房代理(中介)

    租客(客户端)想租房,不会直接找房东(真实业务对象),而是找房产中介(代理对象)。中介帮房东带看、签合同、收押金,租客只和中介沟通,房东只负责收租。

    中介就是房东的代理,租客不直接接触房东。

  2. 明星经纪人

    商家想找明星合作,不会直接联系明星,而是联系经纪人。经纪人负责谈报价、排档期、签合同,明星只负责表演。

    经纪人是明星的代理。

  3. 海外代购

    你想买海外商品,不会亲自出国,而是找代购。代购帮你采购、报关、物流,你只需要付款收货。

    代购是你的代理。

生活代理的核心共性

  1. 存在一个真实对象:拥有核心能力(房东有房、明星会表演、你有购买需求);
  2. 存在一个代理对象:代替真实对象处理辅助工作(中介带看、经纪人谈合作);
  3. 客户端不直接接触真实对象:所有交互都通过代理完成;
  4. 代理不创造核心能力:最终的核心业务还是由真实对象完成。

这就是代理模式的底层逻辑通过代理对象间接访问真实对象,在不修改真实对象的前提下,对功能进行增强或控制访问

1.2 代理模式的官方定义(GoF)

代理模式(Proxy Pattern),也叫委托模式,是GoF23 种设计模式中的结构型设计模式

官方定义:

为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用,可用于隐藏目标对象、增强目标对象功能、控制访问权限等。

简单翻译:

不让客户端直接调用目标对象,而是让代理对象拦在中间,客户端调用代理,代理再调用目标对象,同时代理可以在调用前后做额外操作。

1.3 代理模式的四大核心角色

代理模式的结构非常固定,包含4 个核心角色,所有代理实现(静态 / 动态)都遵循这个结构:

角色名称 英文名称 核心作用 生活类比
抽象主题 Subject 定义真实主题和代理主题的公共接口,保证代理和真实对象对外暴露的方法一致 租房接口(带看、签合同)
真实主题 RealSubject 实现抽象主题,真正执行业务逻辑的对象,是代理最终要调用的目标 房东(真正拥有房子)
代理主题 Proxy 实现抽象主题,持有真实主题的引用,在调用真实主题前后做增强 / 控制 中介(持有房东信息)
客户端 Client 使用代理对象,不直接使用真实主题对象 租客

标准 UML 结构

  1. Subject 接口定义方法;
  2. RealSubject 实现 Subject,实现核心业务;
  3. Proxy 实现 Subject,内部组合 RealSubject;
  4. Client 调用 Proxy 的方法,Proxy 调用 RealSubject 的方法。

1.4 代理模式的核心价值

为什么我们要多一层代理,而不是直接调用真实对象?核心价值有 5 点:

  1. 无侵入增强:不修改真实对象的代码,就能添加日志、事务、缓存等功能;
  2. 访问控制:对真实对象的方法进行权限校验,禁止非法调用;
  3. 远程调用:代理本地对象,实际调用远程服务(Dubbo/RPC);
  4. 懒加载:延迟创建真实对象,节省资源(虚拟代理);
  5. 解耦分离:客户端与真实对象完全解耦,符合软件工程设计原则。

第二部分:静态代理 —— 入门级实现(由浅入深第二步)

2.1 静态代理原理

静态代理是代理模式最基础的实现方式:

  1. 手动编写代理类,代理类和真实类在编译期就已经确定;
  2. 代理类实现抽象主题接口,内部持有真实主题对象
  3. 客户端调用代理类的方法,代理类在前后做增强,再调用真实类的方法。

关键词:编译期生成、手动编码、一对一代理

2.2 静态代理代码实战

我们以用户服务为例,需求:在不修改用户业务代码的前提下,为用户的增删改方法添加日志记录功能。

步骤 1:定义抽象主题(Subject)

创建公共接口 IUserService,定义用户业务方法:

/**
 * 抽象主题:用户服务接口
 */
public interface IUserService {
    // 新增用户
    void addUser(String username);
    // 删除用户
    void deleteUser(Long id);
}

步骤 2:定义真实主题(RealSubject)

实现接口,编写核心业务逻辑(无任何日志代码):

/**
 * 真实主题:用户服务实现类
 * 只关注核心业务,不处理日志、事务等非核心功能
 */
public class UserServiceImpl implements IUserService {
    @Override
    public void addUser(String username) {
        System.out.println("【核心业务】执行新增用户:" + username);
    }

    @Override
    public void deleteUser(Long id) {
        System.out.println("【核心业务】执行删除用户:" + id);
    }
}

步骤 3:定义代理主题(Proxy)

手动编写代理类,实现相同接口,组合真实对象,添加日志增强:

/**
 * 静态代理类:用户服务代理
 * 实现相同接口,持有真实对象引用,添加日志增强
 */
public class UserServiceStaticProxy implements IUserService {
    // 持有真实主题对象(组合关系)
    private final IUserService userService;

    // 构造方法注入真实对象
    public UserServiceStaticProxy(IUserService userService) {
        this.userService = userService;
    }

    @Override
    public void addUser(String username) {
        // 前置增强:打印日志
        System.out.println("【静态代理】前置日志:开始调用addUser方法,参数:" + username);
        // 调用真实主题的核心方法
        userService.addUser(username);
        // 后置增强:打印日志
        System.out.println("【静态代理】后置日志:addUser方法执行完成\n");
    }

    @Override
    public void deleteUser(Long id) {
        System.out.println("【静态代理】前置日志:开始调用deleteUser方法,参数:" + id);
        userService.deleteUser(id);
        System.out.println("【静态代理】后置日志:deleteUser方法执行完成\n");
    }
}

步骤 4:客户端测试(Client)

客户端只使用代理对象,不直接使用真实对象:

/**
 * 客户端:测试静态代理
 */
public class Client {
    public static void main(String[] args) {
        // 1. 创建真实对象
        IUserService realService = new UserServiceImpl();
        // 2. 创建代理对象,注入真实对象
        IUserService proxyService = new UserServiceStaticProxy(realService);
        // 3. 客户端调用代理对象的方法
        proxyService.addUser("张三");
        proxyService.deleteUser(1001L);
    }
}

运行结果

【静态代理】前置日志:开始调用addUser方法,参数:张三
【核心业务】执行新增用户:张三
【静态代理】后置日志:addUser方法执行完成

【静态代理】前置日志:开始调用deleteUser方法,参数:1001
【核心业务】执行删除用户:1001
【静态代理】后置日志:deleteUser方法执行完成

2.3 静态代理优缺点分析

优点

  1. 实现简单:入门门槛低,适合简单场景;
  2. 编译期确定:性能高,无运行时开销;
  3. 职责清晰:真实对象只做核心业务,代理做增强。

缺点(致命痛点)

  1. 代码冗余:一个接口需要一个代理类,100 个接口就要写 100 个代理类;
  2. 维护困难:接口新增方法,所有代理类都必须修改,违反开闭原则;
  3. 扩展性差:无法通用,只能针对特定接口代理。

2.4 静态代理适用场景

静态代理仅适用于代理类数量极少、接口几乎不变化的场景,企业开发中几乎不用,仅作为学习代理模式的入门案例。


第三部分:动态代理 —— 进阶级实现(解决静态代理痛点)

静态代理的核心问题是手动编写代理类,编译期固定,而动态代理彻底解决了这个问题:

动态代理:运行时自动生成代理类字节码,无需手动编写代理类,一个代理类可以代理所有接口 / 类。

Java 中主流的动态代理有两种:

  1. JDK 动态代理:Java 原生,基于接口实现;
  2. CGLIB 动态代理:第三方库,基于继承实现。

3.1 JDK 动态代理(Java 原生,必学)

3.1.1 核心原理

JDK 动态代理是 Java 官方提供的动态代理方案,基于接口实现

  1. 运行时通过反射生成代理类字节码;
  2. 生成的代理类实现目标接口,继承 java.lang.reflect.Proxy 类;
  3. 通过 InvocationHandler 拦截所有方法调用,统一做增强。

3.1.2 核心 API

JDK 动态代理只需要两个核心类:

  1. java.lang.reflect.Proxy:用于生成代理对象的核心类;
    • 核心方法:newProxyInstance(类加载器, 接口数组, 调用处理器)
  2. java.lang.reflect.InvocationHandler:方法调用处理器;
    • 核心方法:invoke(代理对象, 目标方法, 方法参数) → 拦截所有方法。

3.1.3 JDK 动态代理代码实战

我们复用第二部分的 IUserServiceUserServiceImpl不编写任何代理类,实现通用日志代理。

步骤 1:编写通用调用处理器

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

/**
 * JDK动态代理:通用方法调用处理器
 * 所有被代理的方法都会进入invoke方法
 */
public class LogInvocationHandler implements InvocationHandler {
    // 持有真实目标对象
    private final Object target;

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

    /**
     * 拦截所有目标方法的调用
     * @param proxy 代理对象(慎用,避免递归调用)
     * @param method 被调用的目标方法
     * @param args 方法参数
     * @return 方法返回值
     * @throws Throwable 异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置增强:通用日志
        System.out.println("【JDK动态代理】前置日志:方法=" + method.getName() + ",参数=" + (args != null ? args[0] : null));
        // 调用真实目标对象的方法
        Object result = method.invoke(target, args);
        // 后置增强:通用日志
        System.out.println("【JDK动态代理】后置日志:方法=" + method.getName() + " 执行完成\n");
        return result;
    }
}

步骤 2:编写代理工厂(通用生成代理对象)

import java.lang.reflect.Proxy;

/**
 * 代理工厂:通用生成JDK动态代理对象
 */
public class JdkProxyFactory {
    public static Object getProxy(Object target) {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),  // 目标对象的类加载器
                target.getClass().getInterfaces(),   // 目标对象实现的所有接口
                new LogInvocationHandler(target)     // 方法调用处理器
        );
    }
}

步骤 3:客户端测试

/**
 * 客户端:测试JDK动态代理
 */
public class JdkProxyClient {
    public static void main(String[] args) {
        // 1. 创建真实对象
        IUserService realService = new UserServiceImpl();
        // 2. 通过工厂生成代理对象
        IUserService proxyService = (IUserService) JdkProxyFactory.getProxy(realService);
        // 3. 调用代理方法
        proxyService.addUser("李四");
        proxyService.deleteUser(1002L);
    }
}

运行结果

【JDK动态代理】前置日志:方法=addUser,参数=李四
【核心业务】执行新增用户:李四
【JDK动态代理】后置日志:方法=addUser 执行完成

【JDK动态代理】前置日志:方法=deleteUser,参数=1002
【核心业务】执行删除用户:1002
【JDK动态代理】后置日志:方法=deleteUser 执行完成

3.1.4 JDK 动态代理的局限性

  1. 必须实现接口:如果目标类没有实现任何接口,无法使用 JDK 动态代理
  2. 基于反射:性能略低于 CGLIB(高版本 JDK 已优化)。

3.2 CGLIB 动态代理(无接口也能代理)

3.2.1 简介

CGLIB(Code Generation Library)是一个第三方字节码生成框架,Spring、Mybatis 都依赖它。

核心原理:基于继承,运行时生成目标类的子类作为代理对象,重写父类方法实现增强。

3.2.2 核心依赖

Spring 框架已内置 CGLIB,单独使用需引入 Maven 依赖:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

3.2.3 核心 API

  1. Enhancer:代理生成器,用于创建代理对象;
  2. MethodInterceptor:方法拦截器,拦截所有方法调用。

3.2.4 CGLIB 动态代理代码实战

我们创建一个没有实现任何接口的用户服务类,用 CGLIB 实现代理增强。

步骤 1:创建无接口的真实主题

/**
 * 真实主题:无接口的用户服务
 */
public class UserService {
    public void addUser(String username) {
        System.out.println("【核心业务】执行新增用户:" + username);
    }

    public void deleteUser(Long id) {
        System.out.println("【核心业务】执行删除用户:" + id);
    }
}

步骤 2:编写 CGLIB 方法拦截器

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

/**
 * CGLIB动态代理:方法拦截器
 */
public class CglibLogInterceptor implements MethodInterceptor {
    /**
     * 拦截所有方法
     * @param o 代理对象
     * @param method 目标方法
     * @param args 参数
     * @param methodProxy 方法代理(用于调用父类方法,比反射快)
     * @return 返回值
     * @throws Throwable 异常
     */
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 前置增强
        System.out.println("【CGLIB动态代理】前置日志:方法=" + method.getName());
        // 调用父类(真实对象)的方法(CGLIB推荐方式,性能更高)
        Object result = methodProxy.invokeSuper(o, args);
        // 后置增强
        System.out.println("【CGLIB动态代理】后置日志:方法=" + method.getName() + " 执行完成\n");
        return result;
    }
}

步骤 3:编写 CGLIB 代理工厂

import net.sf.cglib.proxy.Enhancer;

/**
 * CGLIB代理工厂
 */
public class CglibProxyFactory {
    public static Object getProxy(Class<?> targetClass) {
        // 1. 创建Enhancer对象
        Enhancer enhancer = new Enhancer();
        // 2. 设置父类(目标类)
        enhancer.setSuperclass(targetClass);
        // 3. 设置方法拦截器
        enhancer.setCallback(new CglibLogInterceptor());
        // 4. 创建代理对象
        return enhancer.create();
    }
}

步骤 4:客户端测试

/**
 * 客户端:测试CGLIB动态代理
 */
public class CglibProxyClient {
    public static void main(String[] args) {
        // 生成代理对象
        UserService proxyService = (UserService) CglibProxyFactory.getProxy(UserService.class);
        // 调用方法
        proxyService.addUser("王五");
        proxyService.deleteUser(1003L);
    }
}

运行结果

【CGLIB动态代理】前置日志:方法=addUser
【核心业务】执行新增用户:王五
【CGLIB动态代理】后置日志:方法=addUser 执行完成

【CGLIB动态代理】前置日志:方法=deleteUser
【核心业务】执行删除用户:1003
【CGLIB动态代理】后置日志:方法=deleteUser 执行完成

3.2.5 CGLIB 注意事项

  1. 不能代理 final 类:final 类无法被继承,CGLIB 会报错;
  2. 不能增强 final 方法:final 方法无法被重写,拦截失效;
  3. 性能优于 JDK 动态代理:基于字节码生成,无反射开销。

3.3 JDK 动态代理 vs CGLIB 动态代理(全面对比)

对比维度 JDK 动态代理 CGLIB 动态代理
实现原理 基于接口,实现目标接口 基于继承,生成目标类子类
依赖要求 Java 原生,无第三方依赖 需引入 CGLIB 依赖(Spring 内置)
限制条件 目标类必须实现接口 目标类不能是 final,方法不能是 final
性能 低版本 JDK 反射较慢,高版本优化 字节码生成,性能更高
Spring 使用 目标类实现接口时默认使用 目标类无接口时使用(Spring Boot2.0 + 默认 CGLIB)
应用场景 接口代理、Mybatis Mapper 无接口类代理、Spring AOP

第四部分:代理模式与七大设计原则深度结合(架构师核心)

软件工程的七大设计原则是架构设计的基石,代理模式之所以成为经典设计模式,核心原因是它完美契合所有七大设计原则。这也是企业面试、架构设计中最常考察的知识点。

我们逐一结合代理模式进行深度解析:

4.1 单一职责原则(Single Responsibility Principle)

原则定义

一个类只负责一项职责,一个类只有一个引起它变化的原因。

代理模式的体现

  1. 真实主题类:只负责核心业务逻辑(如用户增删改);
  2. 代理类:只负责非核心增强逻辑(如日志、事务、权限);
  3. 职责完全分离,互不干扰。

代码佐证

UserServiceImpl 只写业务代码,LogInvocationHandler 只写日志代码,两个类各司其职,完全符合单一职责。

4.2 开闭原则(Open Closed Principle)

原则定义

扩展开放,对修改关闭;软件实体应通过扩展实现变化,而非修改原有代码。

代理模式的体现

  1. 不修改真实主题类:核心业务代码完全不动;
  2. 通过代理扩展功能:新增日志、缓存、事务等功能,只需要新增代理类 / 拦截器;
  3. 拥抱变化,无侵入式扩展。

代码佐证

我们为用户服务添加日志功能,从未修改 UserServiceImpl 一行代码,仅通过动态代理实现扩展,完美符合开闭原则。

4.3 里氏替换原则(Liskov Substitution Principle)

原则定义

子类 / 代理类必须能够替换父类 / 接口,且程序逻辑不变;保证继承 / 实现的正确性。

代理模式的体现

  1. 代理类实现了抽象主题接口
  2. 客户端可以用代理对象无缝替换真实对象,业务逻辑不受影响;
  3. 保证了程序的兼容性和稳定性。

代码佐证

客户端将 realService 替换为 proxyService,业务执行结果完全一致,符合里氏替换原则。

4.4 依赖倒置原则(Dependency Inversion Principle)

原则定义

  1. 高层模块依赖抽象,不依赖具体;
  2. 抽象不依赖具体,具体依赖抽象。

代理模式的体现

  1. 客户端依赖抽象主题接口(IUserService),不依赖具体的真实类(UserServiceImpl)和代理类;
  2. 真实类和代理类都依赖抽象接口;
  3. 彻底解耦高层与底层实现。

代码佐证

客户端代码中,变量类型是 IUserService 接口,而非具体实现类,符合依赖倒置。

4.5 接口隔离原则(Interface Segregation Principle)

原则定义

使用多个专门的接口,不使用单一的总接口;客户端不应依赖不需要的方法。

代理模式的体现

  1. 抽象主题接口是精简的、专门的(如用户服务接口只定义用户方法);
  2. 代理类只实现需要的接口方法,不依赖冗余方法;
  3. 避免接口臃肿,保证接口的单一性。

4.6 迪米特法则(最少知道原则,Law of Demeter)

原则定义

一个对象应当对其他对象有尽可能少的了解;只和直接朋友通信,不和陌生人说话。

代理模式的体现

  1. 客户端只认识代理对象,完全不知道真实对象的存在;
  2. 客户端不依赖真实对象的内部细节,降低系统耦合;
  3. 代理对象屏蔽了真实对象的复杂性。

代码佐证

租客(客户端)只和中介(代理)沟通,不知道房东(真实对象)的任何信息,完美符合迪米特法则。

4.7 合成复用原则(Composite Reuse Principle)

原则定义

优先使用组合 / 聚合关系复用代码,不优先使用继承;继承会导致强耦合。

代理模式的体现

  1. 代理类组合真实对象(持有引用),而非继承真实对象;
  2. 复用真实对象的核心功能,同时避免继承的强耦合;
  3. 灵活、低耦合的复用方式。

代码佐证

静态代理中 UserServiceStaticProxy 持有 IUserService 对象,是组合关系,而非继承,符合合成复用原则。


第五部分:代理模式的分类与企业级实战场景

代理模式根据用途可以分为 6 大类,覆盖企业开发 90% 的场景,我们结合实战讲解:

5.1 远程代理(Remote Proxy)

核心作用

代理远程服务对象,让客户端像调用本地方法一样调用远程服务。

实战场景

Dubbo、Spring Cloud、RMI、RPC 框架的底层核心。

  • 客户端调用本地代理对象;
  • 代理对象通过网络请求调用远程服务器;
  • 屏蔽网络通信细节,简化调用。

5.2 虚拟代理(Virtual Proxy)

核心作用

延迟创建重量级对象,节省资源,实现懒加载。

实战场景

图片加载、大文件加载:

  • 页面先显示代理的占位符图片;
  • 当用户需要查看时,再加载真实高清图片;
  • 避免一次性加载大量资源导致内存溢出。

5.3 保护代理(Protection Proxy)

核心作用

控制真实对象的访问权限,拦截非法调用。

实战场景

权限校验、登录拦截:

  • 代理对象在调用方法前校验用户是否登录、是否有权限;
  • 无权限直接抛出异常,不执行核心业务。

代码示例(保护代理)

// 在invoke方法中添加权限校验
if (!isAdmin(args[0])) {
    throw new RuntimeException("无权限访问!");
}

5.4 缓存代理(Cache Proxy)

核心作用

为真实对象的方法添加缓存,避免重复执行耗时操作。

实战场景

数据查询接口:

  • 代理先查询缓存;
  • 缓存有数据直接返回,无数据再调用真实方法;
  • 提升系统性能。

5.5 日志 / 事务 / 性能监控代理(企业最常用)

核心作用

为业务方法添加非侵入式的日志、事务、性能监控。

实战场景

Spring AOP 的核心实现原理

  • 事务管理:@Transactional 底层通过动态代理实现事务开启 / 提交 / 回滚;
  • 日志记录:统一打印接口日志;
  • 性能监控:统计方法执行耗时。

5.6 Spring AOP 实战:代理模式的终极应用

Spring AOP(面向切面编程)完全基于动态代理实现:

  1. 目标类实现接口 → JDK 动态代理;
  2. 目标类无接口 → CGLIB 动态代理;
  3. 通过切面(Aspect)定义增强逻辑,代理自动织入到目标方法。

这是企业开发中代理模式最核心的应用场景。


第六部分:主流框架源码中的代理模式解析

6.1 Spring AOP 代理创建源码

Spring AOP 通过 AopProxy 接口统一代理创建:

  1. JdkDynamicAopProxy:实现 JDK 动态代理;
  2. CglibAopProxy:实现 CGLIB 动态代理;
  3. DefaultAopProxyFactory:根据目标类自动选择代理方式。

核心源码逻辑:

public AopProxy createAopProxy(AdvisedSupport config) {
    // 目标类有接口 → JDK代理
    if (targetClass.isInterface()) {
        return new JdkDynamicAopProxy(config);
    }
    // 无接口 → CGLIB代理
    return new CglibAopProxy(config);
}

6.2 Mybatis Mapper 代理模式源码

Mybatis 中,我们只写 Mapper 接口,不写实现类,Mybatis 通过 JDK 动态代理生成实现类

  1. MapperProxyFactory:生成代理对象;
  2. MapperProxy:实现 InvocationHandler,拦截接口方法;
  3. 拦截后执行 SQL 语句,返回结果。

核心源码:

public T newInstance(SqlSession sqlSession) {
    MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface);
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), 
            new Class[]{mapperInterface}, mapperProxy);
}

第七部分:代理模式优缺点、适用场景与选型

7.1 代理模式优点

  1. 解耦彻底:客户端与真实对象完全分离;
  2. 无侵入增强:不修改核心代码,扩展功能;
  3. 访问控制:权限、远程、懒加载统一管控;
  4. 通用灵活:动态代理可代理所有类 / 接口;
  5. 符合设计原则:完美契合七大设计原则。

7.2 代理模式缺点

  1. 静态代理冗余:代码量大,维护难;
  2. 动态代理调试复杂:运行时生成类,断点调试困难;
  3. 增加调用层级:性能略有损耗(可忽略)。

7.3 适用场景总结

  1. 需要对方法进行增强(日志、事务、缓存);
  2. 需要控制访问(权限、远程调用);
  3. 需要懒加载重量级对象;
  4. 框架底层设计(Spring、Mybatis、Dubbo)。

7.4 代理模式选型指南

  1. 简单场景、接口固定 → 静态代理;
  2. 目标类实现接口 → JDK 动态代理;
  3. 目标类无接口 → CGLIB 动态代理;
  4. 企业开发 → 直接使用 Spring AOP(底层自动选择代理)。

第八部分:代理模式与相似设计模式的区别

很多新手会混淆代理模式、装饰器模式、适配器模式,我们做核心区分:

8.1 代理模式 vs 装饰器模式

维度 代理模式 装饰器模式
核心目的 控制访问,隐藏真实对象 增强功能,不隐藏对象
关系 代理与真实对象是一对一 装饰器可多层嵌套
客户端 不知道真实对象 知道真实对象,手动装饰
典型场景 权限、远程、事务 IO 流、多层增强

8.2 代理模式 vs 适配器模式

维度 代理模式 适配器模式
核心目的 控制访问,接口不变 转换接口,解决不兼容
接口 代理与真实对象接口相同 适配器将不兼容接口转为兼容接口
典型场景 中介、AOP 旧系统适配新接口

第九部分:代理模式进阶与最佳实践

9.1 动态代理性能优化

  1. 高并发场景优先使用CGLIB
  2. 缓存代理对象,避免重复生成;
  3. Spring Boot 中开启 CGLIB 代理:spring.aop.proxy-target-class=true

9.2 使用禁忌

  1. 不要用代理增强核心业务逻辑(核心逻辑应写在真实类中);
  2. final 类 / 方法无法被 CGLIB 代理,避免滥用 final;
  3. 不要过度使用代理,增加系统复杂度。

9.3 企业最佳实践

  1. 统一使用Spring AOP实现日志、事务、监控;
  2. 底层框架设计优先使用动态代理
  3. 代理逻辑保持精简,不写复杂业务代码。

第十部分:总结

代理模式是 Java 架构师必须掌握的核心设计模式,本文从生活案例→静态代理→动态代理→设计原则→框架源码→实战场景全方位拆解,核心知识点总结:

  1. 本质:通过代理对象间接访问真实对象,实现控制与增强;
  2. 实现:静态代理(入门)、JDK 动态代理(接口)、CGLIB 动态代理(无接口);
  3. 核心价值:无侵入增强、解耦、访问控制;
  4. 设计原则:完美契合七大设计原则,是架构设计的典范;
  5. 企业应用:Spring AOP、Mybatis、Dubbo 的底层核心。

掌握代理模式,不仅能让你写出更优雅、更易维护的代码,更能让你读懂主流框架的底层原理,完成从初级程序员到 Java 架构师的蜕变。

posted @ 2026-04-01 20:23  bright_ye  阅读(11)  评论(0)    收藏  举报