代理模式(Proxy Pattern)是设计模式中的一种结构型模式,它为其他对象提供一种代理以控制对这个对象的访问。代理模式在不改变目标对象功能的前提下,为目标对象添加额外的处理逻辑或控制,比如权限验证、日志记录、事务处理等。通过引入代理对象,可以使得客户端代码与真实目标对象之间解耦,从而增强系统的灵活性和可扩展性。

代理模式的结构 代理模式主要包含三种角色:

抽象主题角色(Subject):定义代理类和真实主题的公共接口,这样可以在任何使用真实主题的地方都可以使用代理。 真实主题角色(Real Subject):定义了代理角色所代表的真实对象,是代理对象所代理的实体。 代理主题角色(Proxy Subject):代理角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象;同时,代理角色可以在执行真实主题前后添加一些附加的操作,相当于对真实主题对象进行封装。 代理模式的分类 根据代理的创建时期,代理模式可以分为两种:

静态代理:代理类在程序运行前就已经存在,一般由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经被创建。 动态代理:动态代理类的源码是在程序运行时由JVM根据反射等机制动态生成的,所以不存在代理类的字节码文件。与静态代理类相比,动态代理更加灵活,但每次调用代理方法时,动态代理机制都会创建一个新的代理实例对象,所以速度相对较慢。 使用场景 远程代理(Remote Proxy):为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是本机的不同进程,也可以是网络上的一台远程服务器。 虚拟代理(Virtual Proxy):根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。 保护代理(Protect or Access Proxy):控制对原始对象的访问。保护代理用于控制不同用户对真实对象的访问权限。 智能指引(Smart Reference Proxy):提供了比简单调用更多的服务。例如,实现了自动缓存,当再次访问同一资源时,可以从缓存处直接返回,而不需要再次去创建或查询。 优缺点 优点:

代理模式能够协调调用者和被调用者,降低系统的耦合度。 在客户端和目标对象之间起到一个中介作用和保护目标对象的作用。 可以通过代理类添加额外的功能。 缺点:

代理模式会造成系统设计中类的数量增加。 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢。 增加了系统的复杂度。

下面我将分别提供一个使用JDK动态代理和CGLIB代理的案例。

JDK动态代理案例 首先,我们需要定义一个接口和一个实现了该接口的类。然后,我们将创建一个动态代理类,该类将在运行时动态生成,并用于代理对真实对象的调用。 接口定义

public interface HelloService {  
    String sayHello(String name);  
}

真实类实现

public class HelloServiceImpl implements HelloService {  
    @Override  
    public String sayHello(String name) {  
        return "Hello, " + name;  
    }  
}

JDK动态代理实现

import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;  
  
public class JdkProxyFactory {  
  
    // 创建一个动态代理类  
    public static <T> T getProxyInstance(Class<T> interfaceClass, InvocationHandler handler) {  
        return (T) Proxy.newProxyInstance(  
                interfaceClass.getClassLoader(), // 类加载器  
                new Class<?>[]{interfaceClass},   // 需要代理的接口  
                handler                           // 调用处理器  
        );  
    }  
  
    public static void main(String[] args) {  
        HelloService realService = new HelloServiceImpl();  
        HelloService proxyService = JdkProxyFactory.getProxyInstance(  
                HelloService.class,  
                (proxy, method, args1) -> {  
                    System.out.println("Before method call");  
                    Object result = method.invoke(realService, args1);  
                    System.out.println("After method call");  
                    return result;  
                }  
        );  
  
        String result = proxyService.sayHello("World");  
        System.out.println(result);  
    }  
}

CGLIB代理案例 CGLIB代理是通过继承被代理类来创建代理对象的,因此它不需要接口。但是,由于它基于继承,所以无法代理final类或者final方法。

真实类定义(无需接口)

public class HelloService {  
    public String sayHello(String name) {  
        return "Hello, " + name;  
    }  
}

CGLIB代理实现 注意:CGLIB库不是JDK自带的,你需要通过Maven或Gradle等构建工具来引入它。

<!-- Maven依赖 -->  
<dependency>  
    <groupId>cglib</groupId>  
    <artifactId>cglib</artifactId>  
    <version>3.3.0</version>  
</dependency>
import net.sf.cglib.proxy.Enhancer;  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  
  
import java.lang.reflect.Method;  
  
public class CglibProxyFactory {  
  
    public static <T> T getProxyInstance(Class<T> clazz, MethodInterceptor interceptor) {  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(clazz);  
        enhancer.setCallback(interceptor);  
        return (T) enhancer.create();  
    }  
  
    public static void main(String[] args) {  
        HelloService realService = new HelloService();  
        HelloService proxyService = CglibProxyFactory.getProxyInstance(  
                HelloService.class,  
                (obj, method, args, proxy) -> {  
                    System.out.println("Before method call");  
                    Object result = method.invoke(realService, args);  
                    System.out.println("After method call");  
                    return result;  
                }  
        );  
  
        String result = proxyService.sayHello("World");  
        System.out.println(result);  
    }  
}

在CGLIB的代理实现中,我们使用了Enhancer类来生成代理对象,并通过MethodInterceptor接口的实现来定义在方法调用前后的行为。

请注意,由于CGLIB代理是通过继承实现的,因此它不能代理final类或者final方法。此外,由于它需要在运行时生成新的类,因此可能会有一定的性能开销。而JDK动态代理则依赖于接口,因此不能代理没有实现接口的类。在选择使用哪种代理方式时,你需要根据你的具体需求来做出决定。

非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤ 分享👥 留言💬thanks!!!