Java代理
代理模式
代理模式又叫委托模式,是为某个对象提供一个代理对象,并且由代理对象控制对原对象的访问。通过代理对象对原对象的方法功能进行增强或是添加一些预处理、后处理操作。
为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。
按照代理类的创建时间可以分为静态代理和动态代理:
静态代理:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的class文件就已经存在
动态代理:程序运行期通过反射机制动态的生成
静态代理
被代理类和代理类需要实现相同的接口或继承相同父类;
代理类中包含一个被代理类对象;
调用功能时代理者会调用被代理者的功能,同时附加新的操作
/** * 共同接口 */ public interface SellPhone { void sellPhone(); } /** * 被代理类 */ public class SellPhoneImpl implements SellPhone { @Override public void sellPhone() { System.out.println("销售手机~"); } } /** * 代理类 */ public class SellPhoneImplProxy implements SellPhone { private SellPhoneImpl sellPhone; public SellPhoneImplProxy(SellPhoneImpl sellPhone) { this.sellPhone = sellPhone; } @Override public void sellPhone() { System.out.println("售前方法~"); sellPhone.sellPhone(); System.out.println("售后方法~"); } } /** * 测试 */ public class TestProxy { public static void main(String[] args) { SellPhoneImpl sellPhone = new SellPhoneImpl(); SellPhoneImplProxy sellPhoneImplProxy = new SellPhoneImplProxy(sellPhone); sellPhone.sellPhone(); sellPhoneImplProxy.sellPhone(); } }
缺点
一个代理类只能适应一种业务,如果有新业务或者业务变动,需要实现新接口复写新的代理类或同时修改接口及实现类。
代理类与被代理类需要实现相同方法,会产生大量冗余代码。
动态代理
对代理模式而言,一般来说,被代理类与其代理类是一一对应的,这也是静态代理的特点。但是也存在这样的情况:多个代理类所做的操作相同,如统计方法调用次数、添加日志功能等等。如果是静态代理则每个代理类都含有相同的公共方法。
在动态代理中,代理类是在运行时期生成的。因此,相比静态代理,动态代理可以很方便地对委托类的相关方法进行统一增强处理。
JDK动态代理
特点
jdk动态代理是基于接口的,被代理类必须是某个接口的实现类。
jre自带,不需要引入外部依赖。
java.lang.reflect.Proxy
:
该类用于动态生成代理类,主要的静态方法 newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
java.lang.reflect.InvocationHandler
:
该接口只有一个invoke方法,通过该方法实现对委托类的代理的访问,是代理类完整逻辑的集中体现,包括要切入的增强逻辑和进行反射执行的真实业务逻辑都在此实现。
步骤:
1. 被代理类实现接口
2. 新建代理类,实现 InvocationHandler 接口,在构造方法中传入一个 object 对象,实现 invoke 方法,在该方法中进行相关增强处理
3. 调用 Proxy 类的静态方法 newProxyInstance(...),new 代理类作为 InvocationHandler 参数,new 被代理类,获取其类加载器,全部接口
4. 调用 Proxy 类的 newProxyInstance(...) 生成的新类
CGLIB动态代理
特点
通过继承实现,被代理类必须能够被继承。通过被代理类创建子类,子类就是父类的代理。只能代理父类的公共方法。