动态代理是实现AOP的绝好底层技术

JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中 InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一 起。而Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例。这样讲一定很抽象,我们马上着手动用Proxy和InvocationHandler这两个魔法戒对上一节中的性能监视代码进行AOP式的改造。
首先,我们从业务类ForumServiceImpl 中删除性能监视的横切代码,使ForumServiceImpl只负责具体的业务逻辑,如所示:
代码清单 5 ForumServiceImpl:移除性能监视横切代码

public class ForumServiceImpl implements ForumService {
 4 
 5  public void removeTopic(int topicId) {
 6          ①
 7   System.out.println("模拟删除Topic记录:"+topicId);
 8   try {
 9    Thread.currentThread().sleep(20);
10   } catch (Exception e) {
11    throw new RuntimeException(e);
12   }
13    ②
14  }
15  public void removeForum(int forumId) {
16          ①
17   System.out.println("模拟删除Forum记录:"+forumId);
18   try {
19    Thread.currentThread().sleep(40);
20   } catch (Exception e) {
21    throw new RuntimeException(e);
22   }
23          ②
24  }
25 }

在代码清单 5中的①和②处,原来的性能监视代码被移除了,我们只保留了真正的业务逻辑。
    从业务类中移除的横切代码当然还得找到一个寄居之所,InvocationHandler就是横切代码的家园乐土,我们将性能监视的代码安置在PerformaceHandler中,如代码清单 6所示:
代码清单 6 PerformaceHandler

2 import java.lang.reflect.InvocationHandler;
 3 import java.lang.reflect.Method;
 4 
 5 public class PerformaceHandler implements InvocationHandler {
 6     private Object target;
 7  public PerformaceHandler(Object target){//①target为目标的业务类
 8   this.target = target;
 9  }
10  public Object invoke(Object proxy, Method method, Object[] args)
11    throws Throwable {
12   PerformanceMonitor.begin(target.getClass().getName()+"."+ method.getName());
13   Object bj = method.invoke(target, args);//②通过反射方法调用目标业务类的业务方法
14   PerformanceMonitor.end();
15   return obj;
16  }
17 }

粗体部分的代码为性能监视的横切代码,我们发现,横切代码只出现一次,而不是原来那样星洒各处。大家注意②处的method.invoke(),该语句通 过反射的机制调用目标对象的方法,这样InvocationHandler的invoke(Object proxy, Method method, Object[] args)方法就将横切代码和目标业务类代码编织到一起了,所以我们可以将InvocationHandler看成是业务逻辑和横切逻辑的编织器。下面, 我们对这段代码做进一步的说明。
首先,我们实现InvocationHandler接口,该接口定义了一个 invoke(Object proxy, Method method, Object[] args)的方法,proxy是代理实例,一般不会用到;method是代理实例上的方法,通过它可以发起对目标类的反射调用;args是通过代理类传入 的方法参数,在反射调用时使用。
    此外,我们在构造函数里通过target传入真实的目标对象,如①处所示,在接口方法invoke(Object proxy, Method method, Object[] args)里,将目标类实例传给method.invoke()方法,通过反射调用目标类方法,如②所示。
    下面,我们通过Proxy结合PerformaceHandler创建ForumService接口的代理实例,如代码清单 7所示:
代码清单 7 TestForumService:创建代理实例

2 import java.lang.reflect.Proxy;
 3 public class TestForumService {
 4  public static void main(String[] args) {
 5   ForumService target = new ForumServiceImpl();//①目标业务类
 6 //② 将目标业务类和横切代码编织到一起
 7   PerformaceHandler handler = new PerformaceHandler(target);
 8          //③为编织了目标业务类逻辑和性能监视横切逻辑的handler创建代理类
 9   ForumService proxy = (ForumService) Proxy.newProxyInstance(
10 target.getClass().getClassLoader(),
11     target.getClass().getInterfaces(),
12  handler);
13          //④ 操作代理实例
14   proxy.removeForum(10);
15   proxy.removeTopic(1012);
16  }
17 }

上面的代码完成了业务类代码和横切代码编织和接口代理实例生成的工作,其中在②处,我们将ForumService实例编织为一个包含性能监视逻辑的 PerformaceHandler实例,然后在③处,通过Proxy的静态方法newProxyInstance()为融合了业务类逻辑和性能监视逻辑 的handler创建一个ForumService接口的代理实例,该方法的第一个入参为类加载器,第二个入参为创建的代理实例所要实现的一组接口,第三 个参数是整合了业务逻辑和横切逻辑的编织器对象。
按照③处的设置方式,这个代理实例就实现了目标业务类的所有接口,也即ForumServiceImpl的ForumService接口。这样,我们就可以按照调用ForumService接口的实例相同的方式调用代理实例,如④所示。运行以上的代码,输出以下的信息:

模拟删除Forum记录:10
end monitor
com.baobaotao.proxy.ForumServiceImpl.removeForum花费47毫秒。

begin monitor
模拟删除Topic记录:1012
end monitor
com.baobaotao.proxy.ForumServiceImpl.removeTopic花费26毫秒。

我们发现,程序的运行效果和直接在业务类中编写性能监视逻辑的效果一致,但是在这里,原来分散的横切逻辑代码已经被我们抽取到 PerformaceHandler中。当其它业务类(如UserService、SystemService等)的业务方法也需要使用性能监视时,我们 只要按照以上的方式,分别为它们创建代理对象就可以了。下面,我们用时序图描述调用关系,进一步代理实例的本质,如图1所示:
 
                                图 1代理实例的时序图
    我们在上图中特别使用虚线阴影的方式对通过代理器创建的ForumService实例进行凸显,该实例内部利用PerformaceHandler整合横 切逻辑和业务逻辑。调用者调用代理对象的的removeForum()和removeTopic()方法时,上图的内部调用时序清晰地告诉了我们实际上所 发生的一切。

AOP-----动态代理(转)的更多相关文章

  1. 技术的正宗与野路子 c#, AOP动态代理实现动态权限控制(一) 探索基于.NET下实现一句话木马之asmx篇 asp.net core 系列 9 环境(Development、Staging 、Production)

    黄衫女子的武功似乎与周芷若乃是一路,飘忽灵动,变幻无方,但举手抬足之间却是正而不邪,如说周芷若形似鬼魅,那黄衫女子便是态拟神仙. 这段描写出自<倚天屠龙记>第三十八回. “九阴神抓”本是& ...

  2. Spring学习笔记之aop动态代理(3)

    Spring学习笔记之aop动态代理(3) 1.0 静态代理模式的缺点: 1.在该系统中有多少的dao就的写多少的proxy,麻烦 2.如果目标接口有方法的改动,则proxy也需要改动. Person ...

  3. String Aop 动态代理例子

    动态代理原理:spring AOP采用动态代理来实现 (1)定义一个接口Boy package aop001; public interface Boy { public void beat(Stri ...

  4. Spring AOP 动态代理 缓存

    Spring AOP应用:xml配置及注解实现. 动态代理:jdk.cglib.javassist 缓存应用:高速缓存提供程序ehcache,页面缓存,session缓存 项目地址:https://g ...

  5. AOP动态代理解析4-代理的创建

    做完了增强器的获取后就可以进行代理的创建了 AnnotationAwareAspectJAutoProxyCreator->postProcessAfterInitialization-> ...

  6. AOP动态代理解析1-标签的解析

    spring.handlers http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespa ...

  7. spring aop 动态代理批量调用方法实例

    今天项目经理发下任务,需要测试 20 个接口,看看推送和接收数据是否正常.因为对接传输的数据是 xml 格式的字符串,所以我拿现成的数据,先生成推送过去的数据并存储到文本,以便验证数据是否正确,这时候 ...

  8. Spring AOP动态代理原理与实现方式

    AOP:面向切面.面向方面.面向接口是一种横切技术横切技术运用:1.事务管理: (1)数据库事务:(2)编程事务(3)声明事物:Spring AOP-->声明事物   2.日志处理:3.安全验证 ...

  9. spring AOP 动态代理和静态代理以及事务

    AOP(Aspect Oriented Programming),即面向切面编程 AOP技术,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装 ...

  10. spring源码-aop动态代理-5.3

    一.动态代理,这是一个很强大的东西哦.研发过程中我们会常用很多业务类,但是存在一个问题.如何在不修改源码逻辑的情况下,加入自己的相关逻辑.比如异常处理,日志记录等! 二.Java动态代理的两种方式JD ...

随机推荐

  1. iframe 重新加载闪过白块问题

    在使用iframe时,iframe背景为白块,刷新时也会闪过白块.如果刷新时间长,就会一直出现白块,让人很烦恼,通过网上搜资料,测试最终解决方法如下所示,注意主要针对IE浏览器测试. 一.iframe ...

  2. Foundation--NSArray+NSMutableArray

    C语言中数组只能存放一种类型 OC语言中数组可以存放多种类型,但是只能是对象类型,不可以是基本类型 我们实际中最好在一个数组中只存放一种类型的元素 nil表示数组的结尾,所以我们不能填写值为nil的对 ...

  3. css基础之 font的简写规则 以及 自定义 CSS3 @font-face详细用法

    Part 1 font简写 CSS的命名规则是用英文字母 数字 和下划线(一般用小写)来命名.简写css font的好处有三:一是写起来方便(就像键盘快捷键):二是简化代码:三是帮助你熟悉和深刻理解c ...

  4. jquery 判断多组radio checkbox是否选中

    最近要做一个问卷调查的小页面,需要判断用户是否每项都有选择,如果每个都挨个判断很苦逼,所以网上搜了搜,自己也总结了一下,写了一段小代码~哈哈,水平有限大家见谅.html代码就不上了,N多单选和多选框就 ...

  5. 使用SQLiteHelper创建数据库并插入数据

    参考<疯狂android讲义>8.4节P424 1.获取SQLiteDatabase实例有2种方法,一是直接new SQLiteDatabase(),另一种使用SQLiteHelper.一 ...

  6. 转载:EntityFramework 6.0< Code First > 连接 Mysql数据库

    转载自:http://blog.csdn.net/kmguo/article/details/19650299 网上有很多关于用EntityFrame来连接Mysql数据库的教程,可是很多并不靠谱,转 ...

  7. SQL Server 分区表的创建方法与管理

    背景知识: 分区表.可以把表中的数据按范围保存到不同的文件组中. 举个例子吧: 2014年以前的数据保存到文件组A 2014~2015的数据保存到文件组B 2015年以后的数据保存到文件组C 好处: ...

  8. Python 函数 切片 迭代 列表生成器

    函数 编写     定义一个函数要用def语句    def sum(i,n):   ⚠有冒号 返回多值     实际上是返回一个tuple 定义默认参数    默认参数的作用是简化调用   def ...

  9. nginx上传模块—nginx upload module-

    一. nginx upload module原理 官方文档: http://www.grid.net.ru/nginx/upload.en.html Nginx upload module通过ngin ...

  10. NFC的安全性

    NFC近距离无线技术具有快捷.易用.安全等特性,其中安全是支付行业最关心的特性. 众所周知传统磁条银行卡的账号信息,是记录在磁条中,当进行刷卡交易时,POS机将交易金额,银行卡中的账号信息以及用户输入 ...