代理模式详解:静态代理与动态代理的实现

静态代理

eg: 我们在商店买商品,而商店的商品又来源于厂商,此时商店的作用便是代理

1. 定义服务接口

java 复制代码
public interface UserService {
    void select();
    void update();
}

2. 实现服务接口的类

java 复制代码
public class UserServiceImpl implements UserService {
    @Override
    public void select() {
        System.out.println("这是查找");
    }

    @Override
    public void update() {
        System.out.println("这是修改");
    }
}

3. 创建代理类

代理类同样实现 UserService 接口,并在其中添加扩展逻辑。

java 复制代码
public class UserServiceProxy implements UserService {
    private UserServiceImpl userService = new UserServiceImpl();

    @Override
    public void select() {
        long begin = System.currentTimeMillis();
        userService.select();
        long end = System.currentTimeMillis();
        System.out.println("select执行时间为" + (end - begin) + "毫秒");
    }

    @Override
    public void update() {
        long begin = System.currentTimeMillis();
        userService.update();
        long end = System.currentTimeMillis();
        System.out.println("update执行时间为" + (end - begin) + "毫秒");
    }
}

静态代理的问题

虽然静态代理允许我们在不修改原有业务逻辑代码的情况下添加额外逻辑,但它也存在以下缺点:

  1. 代理类数量繁多:当有多个目标类时,需要为每个目标类创建对应的代理类,导致代理类数量激增。
  2. 耦合度高:如果在接口中增加或修改功能,需要同时修改实现类和代理类,降低了代码的灵活性。

动态代理

动态代理利用 JDK 的反射机制,能够在运行时创建代理对象,避免了静态代理的缺点。

动态代理的实现方式

  • 基于jdk的动态代理:使用java反射技术实现(主要有invocatoionHandler接口,Method和Proxy类)
  • 基于cglib动态代理:cglib为第三方的工具库,主要用来创建代理对象。目标类只需要继承cglib生成一个被代理对象的子类作为代理(核心为:MethodIntercepter接口和Enhancer类)

注意:基于jdk动态代理必须要实现接口,若是没有实现接口则使用cglib来创建动态代理

其中:

  1. Method类:
  • method表示代理所调用的目标方法
  1. Proxy类
  • 通过该类可以生成代理对象,代理对象的创建是由jdk提供的,我们只是负责调Proxy类中的方法来拿到这个代理对象
  • 调用Proxy类中的静态方法newProxyInstance()来创建一个代理对象
java 复制代码
  public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
  • newProxyInstance参数说明:
    • loader表示目标对象的类加载器,固定写法:目标对象.getClass().getClassLoader();
    • interfaces表示目标对象所实现的接口,接口多继承,因此是个数组。固定写法:目标对象.getClass().getInterface();
    • h表示代理类所要完成的功能
      返回值就是代理类对象,并且在该对象创建时已经说明了,该代理类对象所代理的目标对象是谁,该目标对象完成了那些功能,该代理类所要完成的功能

JDK 动态代理的步骤

  1. 定义被代理的接口
java 复制代码
public interface OrderService {
    void create();
}
  1. 实现被代理接口的类
java 复制代码
public class OrderServiceImpl implements OrderService {
    @Override
    public void create() {
        System.out.println("执行创建订单");
    }
}
  1. 创建代理类并实现 InvocationHandler 接口
java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class PerformanceInvocationHandler implements InvocationHandler {
    private Object real;

    public PerformanceInvocationHandler(Object real) {
        this.real = real;
    }

   /**
     * @param proxy  代理对象
     * @param method 当前执行的方法对象
     * @param args   参数列表
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long begin = System.currentTimeMillis();
        Object result = method.invoke(real, args);
        long end = System.currentTimeMillis();
        System.out.println("执行方法耗时" + (end - begin) + "毫秒");
        return result;
    }
}
  1. 测试动态代理
java 复制代码
import java.lang.reflect.Proxy;

public class Test01 {
    public static void main(String[] args) {
        // 创建被代理对象
        OrderServiceImpl orderService = new OrderServiceImpl();
        
        // 获取类加载器
        ClassLoader classLoader = orderService.getClass().getClassLoader();
        
        // 获取接口
        Class<?>[] interfaces = orderService.getClass().getInterfaces();
        
        // 创建 InvocationHandler
        PerformanceInvocationHandler handler = new PerformanceInvocationHandler(orderService);
        
        // 创建动态代理对象
        OrderService orderServiceProxy = (OrderService) Proxy.newProxyInstance(classLoader, interfaces, handler);
        
        // 调用代理的方法
        orderServiceProxy.create();
    }
}

输出结果

执行创建订单
执行方法耗时1毫秒

总结

通过使用静态代理和动态代理模式,我们能够有效地扩展对象的功能而无需修改原有业务逻辑。尽管静态代理适用于简单场景,但随着系统的复杂性增加,动态代理提供了更高的灵活性和可扩展性,尤其是在处理多个目标对象时。

相关推荐
编程、小哥哥6 小时前
设计模式之代理模式(模拟mybatis-spring中定义DAO接口,使用代理类方式操作数据库原理实现场景)
设计模式·mybatis·代理模式
小白不太白9501 天前
设计模式之 代理模式
设计模式·代理模式
吾与谁归in3 天前
【C#设计模式(13)——代理模式(Proxy Pattern)】
设计模式·c#·代理模式
OkeyProxy4 天前
什麼是ISP提供的公共IP地址?
代理模式·proxy模式·ip地址·isp·海外ip代理
kikyo哎哟喂4 天前
Java 代理模式详解
java·开发语言·代理模式
hxj..4 天前
【设计模式】代理模式
java·设计模式·代理模式·动态代理
武子康5 天前
Java-05 深入浅出 MyBatis - 配置深入 动态 SQL 参数、循环、片段
java·sql·设计模式·架构·mybatis·代理模式
武子康6 天前
Java-04 深入浅出 MyBatis - SqlSessionFactory 与 SqlSession DAO与Mapper 代理模式
java·mysql·spring·mybatis·springboot·代理模式
南城花随雪。7 天前
Mybatis框架之代理模式 (Proxy Pattern)
mybatis·代理模式
JhonKI9 天前
【算法】动态规划中01背包问题解析
算法·动态规划·代理模式