博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
动态代理
阅读量:4223 次
发布时间:2019-05-26

本文共 4768 字,大约阅读时间需要 15 分钟。

代理模式

  • 定义:为其他对象提供一种代理机制,以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。-《设计模式》

  • 在代理模式下,有一个是真正的你要访问的对象(目标类),一个是代理对象,真正对象与代理对象实现同一个接口,先访问代理类再访问真正要访问的对象。

  • 代理模式分为静态代理、动态代理

静态代理

  • 静态代理是由程序员创建或工具生成代理类的源码,再编译代理类。
  • 所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
//主题接口,后续类需要实现此接口public interface Subject {    public void doSomething();}
//实现上述接口的具体类,表示目标对象public class RealSubject implements Subject {
public void doSomething() { System.out.println("这是真正的对象"); }}
//代理类,如上文所述,需要与目标类实现相同的接口public class ProxySubject implements Subject {
//包含真正目标对象作为成员 private Subject subject; public ProxySubject(Subject subject) { this.subject = subject; } //通过访问代理类实现对目标对象的访问 public void doSomething() { System.out.println("这是一个代理对象"); this.subject.doSomething(); }}
public class ProxyTest {    public static void main(String[] args){        //根据真实对象创建一个代理对象        ProxySubject proxy = new ProxySubject(new RealSubject());        //通过访问代理对象实现对真实对象的访问        proxy.doSomething();    }}

运行结果:

这里写图片描述

  • 优点:代理类接受一个Subject接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。

  • 缺点:代理对象和真实对象高度耦合,每一个代理类都必须实现一遍委托类的接口,如果接口增加方法,则代理类也必须跟着修改;其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。

动态代理

  • 顾名思义,动态代理是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。Java的动态代理有两种方式,传统的jdk动态代理和cglib动态代理,主要区别在于前者通过实现接口,后者通过继承方式。

jdk动态代理

1.通过实现InvocationHandler接口来自定义自己的InvocationHandler;

2.通过Proxy.getProxyClass获得动态代理类
3.通过反射机制获得代理类的构造方法,方法签名为getConstructor(InvocationHandler.class)
4.通过构造函数获得代理对象并将自定义的InvocationHandler实例对象传为参数传入
5.通过代理对象调用目标方法

//实现主题接口的目标类public class ActionImpl_01 implements ActionInf{
public void doSomething(String word) { System.out.println(this.getClass().getName()+"::"+"Hello "+word); }}
//实现InvocationHandler接口public class InvocationHandlerImpl implements InvocationHandler{
private ActionInf object; public InvocationHandlerImpl(ActionInf object) { this.object = object; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("======before invoke======"); System.out.println(proxy.getClass().getName()); Object res = method.invoke(this.object, args); System.out.println("======after invoke======"); return res; } public Object getProxyObject(){ return Proxy.newProxyInstance( Thread.currentThread().getContextClassLoader(), this.object.getClass().getInterfaces(), this ); }}
public class DynamicProxyTest {    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {        ActionImpl_01 a1 = new ActionImpl_01();        //通过构造函数获得代理对象并将自定义的InvocationHandler实例对象传为参数传入         InvocationHandler handler1 = new InvocationHandlerImpl(a1);        //通过Proxy.getProxyClass获得动态代理类        Class proxyClass = Proxy.getProxyClass(ActionInf.class.getClassLoader(), ActionInf.class);        //通过反射机制获得代理类的构造方法,方法签名为getConstructor(InvocationHandler.class)        Constructor constructor = proxyClass.getConstructor(InvocationHandler.class);        //通过代理对象调用目标方法        ActionInf inf = (ActionInf)constructor.newInstance(handler1);        inf.doSomething("world");    }}

运行结果

当然,上述步骤中的2、3、4步也可通过调用Proxy.newProxyInstance()一步完成,读者可以自行查看此方法的实现过程。

上述过程中,我们并没有静态构造实现Subject主题接口的代理类,而是在运行过程中生成了一个名为com.sun.proxy.$Proxy0的代理类,此类运行时生成,结束后销毁,达到了动态的标准。

cglib动态代理

  • CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
//实现cglib动态代理的关键,就是要实现MethodInterceptor(方法拦截器接口)public class CglibProxyImpl implements MethodInterceptor {
private ActionInf object; public CglibProxyImpl(ActionInf object) { this.object = object; } public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("======before invoke======"); ActionInf res = (ActionInf) methodProxy.invokeSuper(o, objects); System.out.println("======after invoke======"); return res; } public ActionInf getProxyObject(){ Enhancer enhancer = new Enhancer(); //设置enhancer对象的父类 enhancer.setSuperclass(this.object.getClass()); //设置enhancer的回调对象 enhancer.setCallback(this); //创建代理对象 return (ActionInf)enhancer.create(); }}
public class DynamicProxyTest {    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {        ActionImpl_01 a1 = new ActionImpl_01();        CglibProxyImpl cg = new CglibProxyImpl(a1);        ActionInf inf = cg.getProxyObject();        inf.doSomething("World");    }}

运行结果

可以看出,cglib通过继承方式基于目标类动态生成一个子类,那很明显一点,cglib不能动态代理final修饰的方法,这点与jdk动态代理有较大差别。

你可能感兴趣的文章
WebGL自学教程——WebGL示例:14.0 代码整理
查看>>
恶心的社会
查看>>
中国式危机公关9加1策略(第五章 慎用信息控制策略)
查看>>
展现自己的人生智慧
查看>>
深入理解java多态性
查看>>
Java新手进阶:细说引用类型
查看>>
osg中使用MatrixTransform来实现模型的平移/旋转/缩放
查看>>
(一) Qt Model/View 的简单说明
查看>>
(二)使用预定义模型 QStringListModel例子
查看>>
UVM:7.4.5 加入存储器
查看>>
UVM:7.5.1 期望值与镜像值
查看>>
UVM:7.5.2 常用操作及其对期望值和镜像值的影响
查看>>
UVM:7.6.1 检查后门访问中hdl 路径的sequence
查看>>
UVM:7.6.2 检查默认值的sequence
查看>>
UVM:7.7.1 使用reg_predictor
查看>>
UVM:7.7.2 使用UVM_PREDICT_DIRECT功能与mirror 操作
查看>>
UVM:7.7.3 寄存器模型的随机化与update
查看>>
UVM:7.7.4 扩展位宽
查看>>
UVM:7.8.1 get_root_blocks
查看>>
UVM:7.8.2 get_reg_by_offset 函数
查看>>