设计模式-代理模式

🔷静态代理

  1. 创建UserService接口
java 复制代码
package com.zr.proxy.staticProxy;

/**
 * @Author: zr
 * @Date: 2025/11/06/13:49
 * @Description:
 */
public interface UserService {
    void addUser();
}
  1. 创建UserServiceImpl,实现UserService接口
java 复制代码
package com.zr.proxy.staticProxy;

/**
 * @Author: zr
 * @Date: 2025/11/06/13:49
 * @Description:
 */
public class UserServiceImpl implements UserService{
    @Override
    public void addUser() {
        System.out.println("addUser方法执行了");
    }
}
  1. 创建静态代理同时也实现UserService接口,

在重写addUser方法时候将原来的实现类UserServiceImpl也引入,

在原来的实现类UserServiceImpl方法执行前后执行前置和后置方法

java 复制代码
package com.zr.proxy.staticProxy;

/**
 * @Author: zr
 * @Date: 2025/11/06/13:50
 * @Description:
 */
public class UserServiceProxy implements UserService{
    private final UserService target;

    public UserServiceProxy(UserService target) {
        this.target = target;
    }


    @Override
    public void addUser() {
        System.out.println("【前置】检查权限");
        target.addUser();
        System.out.println("【后置】记录日志");
    }

    public static void main(String[] args) {
        UserService  target = new UserServiceImpl();
        UserService proxy = new UserServiceProxy(target);
        proxy.addUser();
    }
}
  1. 测试结果

🔥JDK动态代理

  1. UserService和UserServiceImpl复用静态代理的
  2. 创建JdkProxy JDK动态代理
  1. 实现InvocationHandler
  2. 重写invoke方法
  3. 通过newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)获取代理对象
  4. 强转为代理对象正真的类型UserService
java 复制代码
package com.zr.proxy.jdkProxy;

import com.zr.proxy.staticProxy.UserService;
import com.zr.proxy.staticProxy.UserServiceImpl;

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

/**
 * @Author: zr
 * @Date: 2025/11/06/14:15
 * @Description:
 */
public class JdkProxy implements InvocationHandler {
    private final Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("【前置】检查权限");
        Object result  = method.invoke(target, args);
        System.out.println("【后置】记录日志");
        return result;
    }

    public static void main(String[] args) {
        UserService target = new UserServiceImpl();
        UserService proxy = (UserService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new JdkProxy(target));
        proxy.addUser();
    }
}
  1. 测试结果

🔷CGLIB

  1. 引入依赖,使用 Spring 的 cglib(spring-core 内置 ASM 9+),如果JDK17直接用cglib的包会报错
java 复制代码
<!--        <dependency>-->
<!--            <groupId>cglib</groupId>-->
<!--            <artifactId>cglib</artifactId>-->
<!--            <version>3.3.0</version>-->
<!--        </dependency>-->

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.3.30</version>
        </dependency>
  1. 创建一个需要代理的类
java 复制代码
package com.zr.proxy.cglibProxy;

/**
 * @Author: zr
 * @Date: 2025/11/06/14:24
 * @Description:
 */
public class OrderService {
    public void createOrder() {
        System.out.println("执行 createOrder()");
    }
}
  1. 实现Cglib动态代理
  1. 实现MethodInterceptor
  2. 新增一个公共方法getProxy通过Enhancer.create(Class type, Callback callback)获取代理对象
  3. 重写intercept方法,在重写的方法中对被代理的对象的方法实现功能增强
  4. 测试方法中通过new CglibProxy(orderService).getProxy()获取代理对象
  5. 强转为代理对象正真的类型OrderService
java 复制代码
package com.zr.proxy.cglibProxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @Author: zr
 * @Date: 2025/11/06/14:24
 * @Description:
 */
public class CglibProxy implements MethodInterceptor {
    private final Object target;

    public CglibProxy(Object target) {
        this.target = target;
    }
    public Object getProxy(){
        return Enhancer.create(target.getClass(), this);
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("【前置】校验参数");
        Object result  = methodProxy.invoke(target, objects);
        System.out.println("【后置】记录日志");
        return result;
    }

    public static void main(String[] args) {
        OrderService orderService = new OrderService();
        OrderService proxy = (OrderService) new CglibProxy(orderService).getProxy();
        proxy.createOrder();

    }
}
  1. 测试

🙅在 JDK 17 里直接使用 CGLIB 3.3.0 会报模块访问限制异常。

报错核心内容:

plain 复制代码
InaccessibleObjectException: module java.base does not "opens java.lang"

❗报错原因

JDK 9+ 模块化后,java.lang.ClassLoader.defineClass() 不能随便通过反射访问,所以 老版 CGLIB 无法工作

😃解决方案

换成 Spring 自带的 CGLIB(推荐,不需要 opens), Spring 早就把 CGLIB 升级为能兼容 JDK 17 的版本,所以不会出这个问题。

使用 Spring 的 cglib(spring-core 内置 ASM 9+),兼容 JDK 17、21:

在 Maven 中添加:

xml 复制代码
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>5.3.30</version>
</dependency>

👉总结

🔹对比

对比项 静态代理 JDK 动态代理 CGLIB 动态代理
是否需要接口 ✅ 必须有接口 ✅ 必须有接口 ❌ 不需要接口(基于继承)
代理类是否手写 ✅ 要自己写代理类 ❌ 自动生成代理类 ❌ 自动生成子类作为代理
代理实现方式 写死逻辑 反射 + Proxy API ASM 字节码改写,生成子类
性能 中等 中等偏下 ✅ 较高(比 JDK 快)
能否代理 final 类/方法 ✅ 可以 ✅ 可以(接口层代理) ❌ 不能代理 final class 或 final method
框架支持情况 基本不用 Spring AOP 默认策略 Spring AOP 无接口时使用
代码量 多,麻烦
适用场景 小项目、简单增强 面向接口编程时增强 无接口的类,如 Controller、Service

🧩个人总结

  • 静态代理:人为写代理类,麻烦但最直观。
    • ** 一个接口写一个代理类,太累,而动态代理在运行时自动生成。**
  • JDK 动态代理:依赖接口,运行时生成代理类(Proxy)。
    • ** 要求目标类必须实现接口,通过反射实现代理。,否则用不了。 **
  • CGLIB 动态代理:不需要接口,运行时生成子类(Enhancer)。
    • ** 不需要接口,通过生成目标类的子类实现代理,因此无法代理 final 类和方法。**
  • Spring AOP 默认使用 JDK 动态代理,若没有接口则切换为 CGLIB。
相关推荐
guangzan3 小时前
TypeScript 中的单例模式
设计模式
乐悠小码1 天前
Java设计模式精讲---02抽象工厂模式
java·设计模式·抽象工厂模式
乙己4071 天前
设计模式——原型模式(prototype)
设计模式·原型模式
⑩-1 天前
浅学Java-设计模式
java·开发语言·设计模式
攻心的子乐1 天前
软考 关于23种设计模式
java·开发语言·设计模式
成钰1 天前
设计模式之单例模式:一个类就只有一个实例
单例模式·设计模式
o0向阳而生0o1 天前
110、23种设计模式之状态模式(19/23)
设计模式·状态模式
_院长大人_1 天前
设计模式-单例模式
单例模式·设计模式
崎岖Qiu2 天前
【设计模式笔记17】:单例模式1-模式分析
java·笔记·单例模式·设计模式