代理模式(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!!!