加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

JDK动态代理实现简单AOP--转

发布时间:2020-12-14 06:19:24 所属栏目:Java 来源:网络整理
导读:JDK?动态代理是?java?反射的一个重要特性。它在某种方面为?java?提供了动态性的特性,给应用带来了无限的空间。大名鼎鼎的?Hessian?、?Spring AOP?基于动态代理实现。本文将简单的介绍?JDK?动态代理使用。 关于代理模式 代理模式是非常常用的一种设计模式,

JDK?动态代理是?java?反射的一个重要特性。它在某种方面为?java?提供了动态性的特性,给应用带来了无限的空间。大名鼎鼎的?Hessian?、?Spring AOP?基于动态代理实现。本文将简单的介绍?JDK?动态代理使用。

关于代理模式

代理模式是非常常用的一种设计模式,在我们的应用中经常被使用。一般场景是,我们有一个现成的类,它的功能比较的完善了,但是还是存在某些欠缺,这个时候我们需要去扩展一些新的功能,但又不想去重造轮子,这个时候可以使用代理类来替代原来的目标类,通过组合的模式,增加一种为目标类增加一些额外的功能。

代理模式的类结构图一般如下:

?

图1:代理模式类结构图

图2:代理模式序列图

JDK?动态代理

所谓?JDK?动态代理就是在运行时动态生成红色的代理类的过程。和静态代理不一样的地方是静态代理在编译期就要完成代理类?的实现。那么动态代理是如何实现的呢?

根据下面的例子,一步一步来看。

假设有这样一个接口?Speak:

  • public?interface?Speak?{??
  • }??
  • 实现类?PeopleSpeak.

    <div class="dp-highlighter bg_java"><ol class="dp-j" start="1">
    <li class="alt">package?proxy;??

  • public?class?PersonSpeak?implements?Speak?{??
  • ????????System.out.println("hello");??
  • }??
  • 当我们去调用?PersonSpeak?的?sayHello?的时候,很显然是输出?hello?。现在我们需要通过动态代理在运行时动态的生成Speak?的代理类,并在调用?sayHello?方法的前后做一些输出。完成类似?aop?的功能。

    根据以上的思路,我们需要有一个?PersonSpeak?的代理类,它持了?PersonSpeak?的对象,这样就能很方便的完成这个任务。如果用静态代理实现显然是很简单,那么用动态代理如何实现呢?

    这个时候我们可以使用?java?反射里的?Proxy?类。此类是?JDK?动态代理的核心类。?Proxy?类拥有一个在运行期动态创建类的功能。动态的去创建一个?Speak?的子类,同时该子类持有?PersonSpeak?类的一个实例,该子类的功能就是实现上述第一部分代理类的功能。

    关于?java?反射的?Method?、?Field?、?Class?、?Construtor?等这里不做介绍,重点介绍?Proxy和?InvocationHandler?类。

    Proxy和InvocationHandler?类简介

    Proxy?类提供了非常重要的方法,该方法能够动态的生成几个接口的实现类。具体的实现过程由?ProxyGenerator?类来实现,这是比较低层的一个类,这里不做过多描述。同时该动态类需要持有一个实现了?InvocationHandler?接口的子类对象。InvocationHandler?接口的子类对象是我们目标类的又一层代理。对于接口里面的每个方法实现,都是通过调用InvocationHandler?接口的子类对象的反射调用。也就是说动态代理类实际上是?InvocationHandler?子类对象的一个代理。那么?InvocationHandler?子类对象有时我们目标类的代理。通过这样层层代理我们就能实现上述的功能了。这句话可能不是很好理解,但是确实就是这么实现的,也许通过下面的图就能更好的理解:

    ?

    图3:JDK动态代理调用过程

    可以从上图看出来,?JDK?动态反射并不是那么简单的一层代理,而是通过层层代理,最终通过?Method?的反射来调用目标对象的方法,而?aop?的实现可以放在?InvocationHandler?的是实现类里。

    那么根据上述关于动态代理的简介,要实现?PersonSpeak?的?aop?,需要做两件事情

    1. 1.???????实现一个持有?Speak?对象的?InvocationHandler?子类,改子类通过?Mechod?反射调用?PersonSpeak?的方法,并在调用方法前后实现?aop?功能。
    2. 2.???????实现一个能动态创建?Speak?子类的代理类工厂,改工厂能动态的创建?Speak?子类。

    具体实现如下:

    1. SpeakInvocationHandler (?实现?InvocationHandler?接口?)

    可以看出该类的?invoke?方法实现?aop?的关键,所有方法都是通过?invoke?来调用,?invoke?内部通过反射来调用目标对象?target?,同时在调用前后实现了?aop?。

  • import?java.lang.reflect.InvocationHandler;??
  • public?class?SpeakInvocationHandler?implements?InvocationHandler?{??
  • ????SpeakInvocationHandler(Object?target)?{??
  • ????}??
  • ????????System.out.println(method.getName()?+?"?invoked!");??
  • ????????System.out.println(method.getName()?+?"?return!");??
  • ????}??
    1. ProxyFactory

    <div class="dp-highlighter bg_java"><ol class="dp-j" start="1">
    <li class="alt">package?proxy;??

  • import?java.lang.reflect.InvocationHandler;??
  • public?class?ProxyFactory?{??
  • ????InvocationHandler?h;??
  • ????????try?{??
  • ????????????this.h?=?h;??
  • ????????????e.printStackTrace();??
  • ????}??
  • ????????return?Proxy.newProxyInstance(cls.getClassLoader(),?cls.getInterfaces(),?h);??
  • }??
  • ProxyFactory?主要是通过反射的?Proxy?类动态的去创建接口的子类,同时该子类是?InvocationHandler?的一个代理,所有的方法实现,都是通过?InvocationHandler?代理来调用。

    最后来看下?Main?函数:

    <div class="dp-highlighter bg_java"><ol class="dp-j" start="1">
    <li class="alt">package?proxy;??

  • import?java.lang.reflect.InvocationHandler;??
  • ????public?static?void?main(String?args[])?{??
  • ????????InvocationHandler?h?=?new?SpeakInvocationHandler(s);??
  • ????????Speak?speakProxy?=?(Speak)?proxyFactory.createProxyObject();??
  • ????}??
  • 得到的输出结果如下:

    ??sayHello invoked!

    hello

    sayHello return!

    从输出结果可以看出红色的输出部分正是我们通过动态代理来实现的。通过如上的过程完成了正果动态代理的过程。

    除了实现?AOP?,动态代理还可以用于实现远程服务代理。比如说?Hessian?就是通过动态创建远程服务代理类来调用远程服务,从而使应用对远程服务透明化。?Hessian?调用过程如下:

    ?

    图4:Hessian远程服务调用过程

    总结

    JDK?动态代理是?java?反射的一个非常重要的特性,?JDK?动态代理类还可以用来作为?SOAP?的远程服务代理类,总之它在某种程度上提供了?java?的动态性的特点,为应用提供了很大的灵活性。

    原文:http://blog.csdn.net/abing37/article/details/5449401

    (编辑:李大同)

    【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    • 推荐文章
        热点阅读