设计模式-代理模式

🔷静态代理

  1. 创建UserService接口
package com.zr.proxy.staticProxy;

/**
 * @Author: zr
 * @Date: 2025/11/06/13:49
 * @Description:
 */
public interface UserService {
    void addUser();
}
  1. 创建UserServiceImpl,实现UserService接口
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方法执行前后执行前置和后置方法

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
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的包会报错
<!--        <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. 创建一个需要代理的类
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
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 会报模块访问限制异常。

报错核心内容:

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 中添加:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>5.3.30</version>
</dependency>

👉总结

🔹对比

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

🧩个人总结

  • 静态代理:人为写代理类,麻烦但最直观。
    • ** 一个接口写一个代理类,太累,而动态代理在运行时自动生成。**
  • JDK 动态代理:依赖接口,运行时生成代理类(Proxy)。
    • ** 要求目标类必须实现接口,通过反射实现代理。,否则用不了。 **
  • CGLIB 动态代理:不需要接口,运行时生成子类(Enhancer)。
    • ** 不需要接口,通过生成目标类的子类实现代理,因此无法代理 final 类和方法。**
  • Spring AOP 默认使用 JDK 动态代理,若没有接口则切换为 CGLIB。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值