
本文共 4241 字,大约阅读时间需要 14 分钟。
代理模式详解:从静态到动态,再到CGLIB
在软件开发中,我们经常会遇到一个问题:一个类或对象的行为需要通过中介来间接实现,而不是直接操作该对象。这种设计模式就叫做代理模式(Proxy Pattern)。通过本文的深入探讨,你将彻底理解代理模式的核心思想、实现方法以及适用场景。
什么是代理模式?
代理模式可以简单理解为为某一个对象提供一个代理对象,通过代理对象控制对目标对象的引用,最终达到间接调用目标对象的目的。这个概念在现实生活中有着类似的体现。在之前提到的买房例子中,中介公司充当了买房者和卖方之间的桥梁,协助完成整个买房流程。
为什么要使用代理模式?
使用代理模式的主要原因包括:
中介隔离作用:在某些情况下,客户端不应该或无法直接引用目标对象,而代理模式通过中间的代理对象,隔离了目标对象,使其更加安全和便捷。
开闭原则,增加功能:代理模式允许我们在不修改目标对象的情况下,扩展功能。例如,可以在调用目标对象的方法之前或之后,注入额外的功能(比如缓存、日志记录等)。
方便日志和追踪:代理模式使得我们能够在不修改目标对象的情况下,在方法执行前记录日志,或者在返回值后对结果进行处理。
代理模式的实现方式
代理模式可以根据代理对象的创建时间分为两种典型实现方式:
1. 静态代理
静态代理的特点是需要提前为目标对象创建代理类。其主要步骤如下:
创建服务接口
服务接口定义了目标对象的操作规范。例如,二手车交易接口如下:package main.java.proxy;public interface BuyHouse { void buyHouse();}
实现服务接口
目标对象实现该接口,具体行为如下:package main.java.proxy.impl;public class BuyHouseImpl implements BuyHouse { @Override public void buyHouse() { System.out.println("我要买房"); }}
创建代理类
代理类实现同样的接口,并控制对目标对象的调用。例如,房产中介的代理类如下:package main.java.proxy.impl;public class BuyHouseProxy implements BuyHouse { private BuyHouse buyHouse; public BuyHouseProxy(BuyHouse buyHouse) { this.buyHouse = buyHouse; } @Override public void buyHouse() { System.out.println("买房前准备"); buyHouse.buyHouse(); System.out.println("买房后装修"); }}
编写测试类
通过测试类验证代理模式的效果:package main.java.proxy.test;import main.java.proxy.BuyHouse;import main.java.proxy.impl.BuyHouseImpl;public class ProxyTest { public static void main(String[] args) { BuyHouse buyHouse = new BuyHouseImpl(); buyHouse.buyHouse(); BuyHouseProxy buyHouseProxy = new BuyHouseProxy(buyHouse); buyHouseProxy.buyHouse(); }}
优点:开闭原则的应用,通过扩展代理类而非目标类,实现功能的灵活扩展。
缺点:每个服务接口都需要手动创建代理类,工作量大,并且接口变更时,代理类也需要相应修改。2. 动态代理
动态代理则通过代码生成工具或反射机制,在程序运行时动态创建代理对象。它适用于那些接口不容易变更的情况,且需要灵活扩展功能的场景。
动态代理的实现方式主要通过InvocationHandler来处理目标对象的方法调用。例如,动态房产中介代理类如下:
package main.java.proxy.impl;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public 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("买房前准备"); Object result = method.invoke(target, args); System.out.println("买房后装修"); return result; }}
测试类如下:
package main.java.proxy.test;import main.java.proxy.BuyHouse;import main.java.proxy.impl.BuyHouseImpl;import java.lang.reflect.Proxy;public class DynamicProxyTest { public static void main(String[] args) { BuyHouse buyHouse = new BuyHouseImpl(); BuyHouse proxy = (BuyHouse) Proxy.newProxyInstance( BuyHouse.class.getClassLoader(), new Class[]{BuyHouse.class}, new DynamicProxyHandler(buyHouse) ); proxy.buyHouse(); }}
优点:减少手动代理类开发代码量,灵活可扩展。
缺点:动态代理只能代理接口,无法代理本类中的方法,这种限制在实际开发中也带有一定的不便。3. CGLIB代理(增强代理)
CGLIB(Commons-Gateway Language Instrumentation Bridge)通过生成目标对象的子类,动态拦截目标方法进行处理。这种方式适用于需要代理非接口类的对象,但不会对资源密集型的业务逻辑产生性能上的负担。
CGLIB代理类示例如下:
package dan.proxy.impl;import net.sf.cglib-proxy.CGLib;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class CglibProxy implements MethodInterceptor { private Object target; public Object getInstance(Object target) { this.target = target; return CGLib.create.getMethodInterceptor(this); } public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("买房前准备"); Object result = methodProxy.invoke(obj, args); System.out.println("买房后装修"); return result; }}
测试类:
package dan.proxy.test;import dan.proxy.BuyHouse;import dan.proxy.impl.BuyHouseImpl;public class CglibProxyTest { public static void main(String[] args) { BuyHouse house = new BuyHouseImpl(); CglibProxy proxy = new CglibProxy(); BuyHouse proxyHouse = (BuyHouse) proxy.getInstance(house); proxyHouse.buyHouse(); }}
优点:性能优于JDK动态代理,支持非接口类的代理。
缺点:生成的代理类为目标对象的子类,可能存在性能上的开销,且无法代理final方法。发表评论
最新留言
关于作者
