快上网专注成都网站设计 成都网站制作 成都网站建设
成都网站建设公司服务热线:028-86922220

网站建设知识

十年网站开发经验 + 多家企业客户 + 靠谱的建站团队

量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决

大数据开发中动态代理是什么

这篇文章主要介绍了大数据开发中动态代理是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

创新互联坚持“要么做到,要么别承诺”的工作理念,服务领域包括:做网站、网站建设、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的乌海海南网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!

一、动态代理的意义

 首先明白一点,动态代理就是用来生成代理对象的。我们知道传统的代理模式,通常是先定义一个代理类,该代理类需要持有目标对象(也有叫被代理对象,我觉得都行吧)。假设我们有1000个不同的目标对象(这1000个对象不是同一个类),那么我们需要预先定义1000个代理类,这是我们不能容忍的。于是乎,动态代理就出现了,它本质上是生成一个外表上和目标对象一样的代理对象,然后当我们调用代理对象的方法的时候,实际上它在他的方法里面去调用了目标对象对应的同名方法。

二、动态代理设计的核心思想

其实不要把这些设计想得多么高尚,假如我是动态代理设计的作者,由动态代理的意义部分我们知道,我们就是要想尽一切办法,通过目标对象生成代理对象,然后让代理对象的方法调用作用到目标对象的方法调用。没错动态代理的核心思想就是这么简单。比如目标类为Person,Person有一个方法叫做purchase(),此方法用于购物。我们期望purchase()方法有代理类去做处理,比如在购物前记录下购买了哪些东西。我们知道在使用一个类之前,是需要创建一个对象的,我们就在创建的地方动手脚。所以你看到了JDK动态Proxy.newInstance()的方式,也领略过Spring的Enhancer.create()。个人比较喜欢cglib的优雅、干净、利落。吐槽一下JDK的InvocationHandler像极了恶心的中间商。下面是JDK动态代理UML示意图

大数据开发中动态代理是什么

三、JDK动态代理

1,原理

在了解动态代理之前,我们需要了解Java字节码。如果不熟悉Java字节码,你可以理解为通过代码动态生成一个.java文件,然后将其编译为class文件加载到内存中。接下来JDK中的动态代理要做的事情就是怎么去生成一个ProxyPerson字节码文件。其实它就是在生成字节码的时候,持有了InvocationHandler对象,然后去实现了ProxyPerson对应的接口。在该接口的所有实现方法中,只做了一件事情就是调用invocationHandler.invoke()方法。从代码层面来看如下所示:

public class ProxyPerson implements Purchase{

static{   Method method;// 接口的方法   Object[] args;// 接口参数  }
InvocationHandler handler;public ProxyPerson(InvocationHandler handler){    this.handler = handler;}

@overrdepublic purchage(){   this,handler.invoke(this,method,args);  }
}

 那么上面这段代码是在什么时候生成的呢? 

Proxy.newProxyInstance()

在我们调用JDK上面的这个方法的时候,底层就会去生成一个ProxyPerson字节码。知道了原理我们来解答一下JDK动态代理为何只能基于接口代理而不能基于类呢?

1),受限于字节码的生成方式,JDK本身就是基于InvocationHandler去做的代理中转。我们看到代理对象的方法调用于目标对象的调用没有半毛球关系,调用目标对象是我们自己在invoke方法里面完成的。

2),受限于同名的方法只能被向上转型成功的对象调用。比如有两个类Boy与Girl,他们都实现了接口Purchase,如果我们先获取到Girl的purchase()方法method,我们通过method.invoke(new Boy())这样必定会报错。但是如果我们获取到Purchase接口purchase()方法method,我们通过method.invoke(new Boy())这样是ok的,因为new Boy()可以向上转型为Purchase。

2,应用

比如无论是传统的MVC模型还是DDD模型,都离不开Service。我们知道Service方法使用@Transactional是可以开启事务控制的。那么这种注解式事务是如何实现的呢?其实在工程启动的时候,我们就会有一个Bean的后置处理器去检查所有Bean一旦发现Bean的方法上有事务注解,他就通过Proxy.newInstance()去创建一个代理对象,将代理对象进行返回注入,而抛弃原本应该注入到容器的对象。所以我们看起来通过容器拿到的Service其实已经是代理对象了。在调用目标对象前,开启编程式事务即可。

四、cglib动态代理

 有了上面的知识,我们要有对于cglib而言只是在生成字节码上面动手脚的觉悟。下面直观感受与一下生成过程

public static void main(final String[] args) {        Enhancer enhancer = new Enhancer();       enhancer.setSuperclass(Boy.class);       enhancer.setCallback(new MethodInterceptor(){            @Override           public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {               System.out.println("proxy method "+ method.getName());               if(method.getAnnotation(Transactional.class)!=null){                   System.out.println(method.getName()+"发现注解");               }               return methodProxy.invokeSuper(o,args);           }       });       Boy proxy = (Boy) enhancer.create();       proxy.test();     }    public static class Boy{       public void run(){           System.out.println("run...");       }       @Transactional       public void walk(){           System.out.println("walk...");       }       @Transactional       public void test(){           System.out.println("test...");           walk();       }   }

可以看到cglib是基于继承的方式进行字节码动态生成。 它在子类的实现中,只是调用了注入的methodIntercptor.interceptor()方法。 具体字节码实现细节,这里不在深究。 我们在这里探讨一下,为什么cglib可以使同一个service方法中的其他带有事务注解的事务生效?因为基于继承的动态代理,本质发起上调用的代理对象可以向上转型为原本的目标对象,所以它可以直接通过代理对象去调目标对象方法。  

感谢你能够认真阅读完这篇文章,希望小编分享的“大数据开发中动态代理是什么”这篇文章对大家有帮助,同时也希望大家多多支持创新互联,关注创新互联行业资讯频道,更多相关知识等着你来学习!


本文标题:大数据开发中动态代理是什么
标题链接:http://6mz.cn/article/ggchcd.html

其他资讯