代理模式的定义和作用

定义

在 Java 中,代理模式是一种结构型设计模式,它允许通过代理对象来控制对另一个对象(目标对象)的访问。代理对象充当了目标对象的接口,客户端通过代理对象来间接访问目标对象,而不是直接访问目标对象。

作用

  • 增强功能:可以在不修改目标对象代码的前提下,对目标对象的方法进行增强,例如添加日志记录、事务管理、权限验证等功能。
  • 控制访问:代理对象可以控制对目标对象的访问权限,例如在某些情况下限制对目标对象的调用。
  • 远程代理:可以在不同的地址空间中代表另一个对象,使得客户端可以像访问本地对象一样访问远程对象。
  • 延迟加载:在需要使用目标对象时才进行创建和初始化,提高系统性能。

代理的类型

静态代理

静态代理是指在编译时就已经确定了代理类和目标类的关系,代理类和目标类都需要实现相同的接口。代理类在编译时就已经被创建,并且代理类中的方法是固定的,不能在运行时动态改变。

示例代码

// 定义接口
interface Subject {
    void request();
}

// 目标类
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

// 代理类
class ProxySubject implements Subject {
    private RealSubject realSubject;

    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void request() {
        System.out.println("ProxySubject: Before request.");
        realSubject.request();
        System.out.println("ProxySubject: After request.");
    }
}

// 客户端代码
public class StaticProxyExample {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);
        proxySubject.request();
    }
}

优点:实现简单,易于理解和维护。 缺点:代理类和目标类需要实现相同的接口,当接口方法较多时,代理类的代码会变得冗长;并且如果需要代理多个不同的目标类,需要为每个目标类都创建一个对应的代理类,代码复用性较差。

动态代理

动态代理是指在运行时动态地创建代理类和代理对象,不需要在编译时就确定代理类的代码。Java 提供了两种实现动态代理的方式:基于接口的 JDK 动态代理和基于类的 CGLIB 动态代理。

实现动态代理

JDK 动态代理

JDK 动态代理是基于接口的,它只能代理实现了接口的类。实现 JDK 动态代理需要使用 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口。

示例代码

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

// 定义接口
interface Subject {
    void request();
}

// 目标类
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

// 实现 InvocationHandler 接口
class ProxyHandler implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("ProxyHandler: Before method call.");
        Object result = method.invoke(target, args);
        System.out.println("ProxyHandler: After method call.");
        return result;
    }
}

// 客户端代码
public class JdkDynamicProxyExample {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxyHandler proxyHandler = new ProxyHandler(realSubject);
        Subject proxySubject = (Subject) Proxy.newProxyInstance(
                RealSubject.class.getClassLoader(),
                RealSubject.class.getInterfaces(),
                proxyHandler
        );
        proxySubject.request();
    }
}

实现步骤

  1. 定义一个接口和实现该接口的目标类。
  2. 实现 InvocationHandler 接口,在 invoke 方法中实现对目标方法的增强逻辑。
  3. 使用 Proxy.newProxyInstance 方法动态创建代理对象。

CGLIB 动态代理

CGLIB 动态代理是基于类的,它可以代理没有实现接口的类。CGLIB 通过继承目标类来创建代理类,因此目标类不能是 final 类,目标方法也不能是 final 方法。

示例代码

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

// 目标类
class RealSubject {
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

// 实现 MethodInterceptor 接口
class ProxyInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("ProxyInterceptor: Before method call.");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("ProxyInterceptor: After method call.");
        return result;
    }
}

// 客户端代码
public class CglibDynamicProxyExample {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealSubject.class);
        enhancer.setCallback(new ProxyInterceptor());
        RealSubject proxySubject = (RealSubject) enhancer.create();
        proxySubject.request();
    }
}

实现步骤

  1. 引入 CGLIB 依赖。
  2. 定义目标类。
  3. 实现 MethodInterceptor 接口,在 intercept 方法中实现对目标方法的增强逻辑。
  4. 使用 Enhancer 类来创建代理对象。

综上所述,JDK 动态代理适用于代理实现了接口的类,而 CGLIB 动态代理适用于代理没有实现接口的类。在实际开发中,可以根据具体的需求选择合适的动态代理方式。