演进式例解AOP:Java 动态代理

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://haolloyin.blog.51cto.com/1177454/472571

 回顾:

在 Spring 中,除去IoC、DI 核心之外,AOP 是其另一个关键技术。前面渐进式地写了3篇文章简单学习了容器、控制反转(IoC)、读配置文件实现依赖注入(DI),其一:引入容器,Service Locator其二:引入IoC,DI 其三:结合配置文件完善DI

为了学习 AOP,先用例子(同样是前面用过的报表生成例子,不同的需求使得代码结构有了变化)来理解一下Java中的动态代理。

问题描述:

开发一个能够根据本地文件路径、远程文件路径生成HTML、PDF格式的报表的应用。由于不同操作系统下的文件路径有不同的路径分隔符,因此这里存在一个特殊要求:接收到文件路径生成报表之前必须验证该文件路径的合法性。

解决方案:

为了重用我们前面的报表生成的代码(先假设着吧,其实这里类结构已经改变了),在此不能修改原来的代码实现,例如我们不能在原来的 generate() 方法内部增加进行验证的功能实现。此时,用Java 的动态代理(Dynamic Proxy,本质上是反射的应用)可以避开修改原始代码实现来横向增加新功能(AOP也是一种与OOP同等的编程范式,不过目前的我只能这样子简单地理解:-D)。

实现方法:

在 Java 的动态代理技术中,需要关注的是java.lang.reflect 包里面的InvocationHandler接口(最关键)、Proxy类、Method类。代理类需要实现InvocationHandler接口中的 invoke(),使之能够在调用代理类对象的相关方法时,将这一方法的调用转发给目标类(即被代理类,原始类)。

依据代码实现,设计类图如下:

 

 

简单代码实现如下:

  1. package AOP.dynamic_proxy;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. /**
  6.  *  报表生成的公共接口
  7.  */
  8. interface ReportCreator {
  9.     public void getHtmlReport(String path);
  10.     public void getPdfReport(String path);
  11. }
  12. /**
  13.  *  用于根据【本地】文件路径生成报表
  14.  */
  15. class LocalReportCreator implements ReportCreator {
  16.     public void getHtmlReport(String path) {
  17.         System.out.println("根据【本地】文件生成【HTML】格式的报表 ...");
  18.     }
  19.     public void getPdfReport(String path) {
  20.         System.out.println("根据【本地】文件生成【PDF】格式的报表 ...");
  21.     }
  22. }
  23. /**
  24.  *  用于根据【远程】文件路径生成报表
  25.  */
  26. class RemoteReportCreator implements ReportCreator {
  27.     public void getHtmlReport(String path) {
  28.         System.out.println("根据【远程】文件生成【HTML】格式的报表 ...");
  29.     }
  30.     public void getPdfReport(String path) {
  31.         System.out.println("根据【远程】文件生成【PDF】格式的报表 ...");
  32.     }
  33. }

 

  1. /**
  2.  *  动态代理类,实现 InvocationHandler 接口中的 invoke()
  3.  */
  4. class ReportCreatorProxy implements InvocationHandler {
  5.     private ReportCreator targetCreator;
  6.     public ReportCreatorProxy(ReportCreator targetCreator) {
  7.         this.targetCreator = targetCreator;
  8.     }
  9.     /**
  10.      *  实现invoke()方法,增加额外功能
  11.      */
  12.     public Object invoke(Object proxy, Method method, Object[] args)
  13.             throws Throwable {
  14.         // 在生成报表之前添加验证功能,参数即 args,这里简化了
  15.         System.out.println("验证 path 参数是否有效 ...");
  16.         Object result = method.invoke(this.targetCreator, args);
  17.         return result;
  18.     }
  19.     /**
  20.      *  静态工厂方法,用于获取动态代理实例
  21.      */
  22.     public static Object getReportCreator(ReportCreator target) {
  23.         Class targetClass = target.getClass();
  24.         /*
  25.          * loader:  目标类的类加载器
  26.          * interfaces:  目标类已实现的接口
  27.          * handler: 转发方法调用的调用处理类实例,即代理类
  28.          */
  29.         ClassLoader loader = targetClass.getClassLoader();
  30.         Class[] interfaces = targetClass.getInterfaces();
  31.         ReportCreatorProxy handler = new ReportCreatorProxy(target);
  32.         // 创建并返回动态代理类实例
  33.         return Proxy.newProxyInstance(loader, interfaces, handler);
  34.     }
  35. }

 

  1. // 测试
  2. public class DynamicProxy {
  3.     public static void main(String[] args) {
  4.         // 创建目标类对象,即被代理对象、原始对象
  5.         ReportCreator target = new LocalReportCreator();
  6.         // 获取动态代理对象
  7.         ReportCreator reportCreator = (ReportCreator) ReportCreatorProxy
  8.                 .getReportCreator(target);
  9.         // 利用代理对象提供的服务
  10.         reportCreator.getPdfReport("E://test//table.txt");
  11.     }
  12. }

测试运行结果:

验证 path 参数是否有效 ...

根据【本地】文件生成【PDF】格式的报表 ...

上面代码中的验证功能是简化成打印语句了,:-D

 

在前面“回顾”那里我之所以说类结构已经有了相当的变化,是因为我意识到好像建造者模式(Builder)很可能适应于两个例子中的此种变化。

(Builder)建造者模式的Java实现

 

小结:

这里认识一下Java中的动态代理(本质是反射技术的应用),初步感受一下模拟AOP 的处理方式,接下来考虑结合配置文件、DI、动态代理等完善一下AOP的实现。:-D

 

★    以下文章你可能也会感兴趣:

演进式例解控制反转(IoC)、依赖注入(DI)

演进式例解控制反转(IoC)、依赖注入(DI)之二

结合配置文件、反射完善控制反转(IoC)、依赖注入(DI)

 

装饰模式(Decorator)与动态代理的强强联合

(Dynamic Proxy)动态代理模式的Java实现

(Factory Method)工厂方法模式的Java实现

Java RMI 框架的工厂方法模式实现

(Mediator)中介者模式的Java实现(加修改)

 

本文出自 “蚂蚁” 博客,请务必保留此出处http://haolloyin.blog.51cto.com/1177454/472571

  1. da shang
    donate-alipay
               donate-weixin weixinpay

发表评论↓↓