文章目录
- 前言
- 一、代理模式的定义和优、缺点
- 定义
- 优点
- 缺点
- 二、代码演示案例
- 1.静态代理
- 2.JDK动态代理
- 3.CGLIB动态代理
- 总结
前言
代理模式常见的使用场景包括:
需要对对象的访问进行控制或限制的情况。
需要在访问对象时执行额外的操作,例如记录日志、收集统计信息等。。
一、代理模式的定义和优、缺点
定义
代理模式的定义可以概括为:为一个对象提供一个代理对象,以控制对该对象的访问。
优点
1. 访问控制: 代理模式可以在客户端和原始对象之间添加一层间接层,从而实现对原始对象的访问控制。这使得代理对象可以限制客户端对原始对象的直接访问,从而保护原始对象的安全性。
2. 增强原始对象功能: 代理模式允许在访问原始对象时执行额外的操作,例如记录日志、验证用户权限、实现懒加载、缓存结果等。这些额外的功能可以在代理对象中实现,而不需要修改原始对象的代码,从而使得原始对象的功能得到增强。
3. 远程访问: 通过远程代理,客户端可以像调用本地对象一样调用远程对象,而不需要了解网络通信的细节。这使得在分布式系统中使用远程对象变得更加简单和透明。
4. 性能优化: 代理模式可以通过实现缓存代理或虚拟代理来优化系统的性能。例如,缓存代理可以缓存频繁访问的操作结果,从而减少重复计算,提高系统的响应速度。
缺点
1.复杂性增加: 引入代理对象会增加系统的复杂性,因为需要额外的类和接口来实现代理功能。这可能会增加代码量和维护成本。
2.性能损耗: 在某些情况下,代理模式可能会引入额外的性能损耗,特别是在远程代理或虚拟代理的情况下,由于需要进行网络通信或延迟加载,可能会导致一定的性能损耗。
3.可能引入单点故障: 在使用远程代理时,代理对象可能会成为系统的单点故障。如果代理对象出现故障或不可用,可能会导致客户端无法访问远程对象。
4.过多的代理类: 如果系统中存在大量的代理类,可能会导致类的数量过多,增加系统的复杂性和管理成本。
二、代码演示案例
1.静态代理
需要为每一个代理类都手动编写一个对应的代理类。代码如下(示例):
// 接口
interface Subject {void request();
}// 真实主题类
class RealSubject implements Subject {public void request() {System.out.println("RealSubject: Handling request.");}
}// 代理类
class ProxySubject implements Subject {private RealSubject realSubject;public ProxySubject(RealSubject realSubject) {this.realSubject = realSubject;}public void request() {System.out.println("ProxySubject: Logging before request.");realSubject.request();System.out.println("ProxySubject: Logging after request.");}
}// 测试类
public class Main {public static void main(String[] args) {RealSubject realSubject = new RealSubject();ProxySubject proxySubject = new ProxySubject(realSubject);proxySubject.request();}
}
2.JDK动态代理
在动态代理中,要求目标类必须实现接口,然后通过 Proxy 类和 InvocationHandler 接口动态生成代理对象。代码如下(示例):
import java.lang.reflect.*;// 接口
interface Subject {void request();
}// 真实主题类
class RealSubject implements Subject {public void request() {System.out.println("RealSubject: Handling request.");}
}// 动态代理处理器类
class DynamicProxyHandler implements InvocationHandler {private Object target;public DynamicProxyHandler(Object target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("DynamicProxy: Logging before request.");Object result = method.invoke(target, args);System.out.println("DynamicProxy: Logging after request.");return result;}
}// 测试类
public class Main {public static void main(String[] args) {RealSubject realSubject = new RealSubject();InvocationHandler handler = new DynamicProxyHandler(realSubject);Subject proxySubject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),realSubject.getClass().getInterfaces(),handler);proxySubject.request();}
}
3.CGLIB动态代理
CGLIB通过继承目标类来生成代理类的,因此无法代理目标类中的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 TargetClass {public void doSomething() {System.out.println("TargetClass: Doing something...");}
}// 自定义方法拦截器
class CustomMethodInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Before invoking method: " + method.getName());Object result = proxy.invokeSuper(obj, args); // 调用目标方法System.out.println("After invoking method: " + method.getName());return result;}
}public class Main {public static void main(String[] args) {// 创建 Enhancer 对象,用于动态创建目标类的子类Enhancer enhancer = new Enhancer();// 设置目标类的父类enhancer.setSuperclass(TargetClass.class);// 设置方法拦截器enhancer.setCallback(new CustomMethodInterceptor());// 创建代理对象TargetClass proxy = (TargetClass) enhancer.create();// 调用代理对象的方法proxy.doSomething();}
}
总结
每种代理方式都有自己的适用场景和局限性。静态代理适用于简单场景下的代理,但不够灵活;JDK动态代理适用于需要在运行时动态生成代理对象,并且目标类实现了接口的情况;而CGLIB动态代理则适用于对未实现接口的类进行代理。选择合适的代理方式需要根据具体的需求和场景来决定。