应该说AOP原理是Spring技术中最难理解的一个部分,而这个约定游戏也许会给你很多的帮助,通过这个约定游戏,就可以理解Spring AOP的含义和实现方法,也能帮助读者更好地运用Spring AOP到实际的编程当中,这对于正确理解Spring AOP是十分重要的

约定规则

  代码清单:定义Interceptor接口

  1. package com.ssm.chapter11.game;
  2.  
  3. public interface Interceptor {
  4.  
  5. public void before(Object obj);
  6.  
  7. public void after(Object obj);
  8.  
  9. public void afterReturning(Object obj);
  10.  
  11. public void afterThrowing(Object obj);
  12.  
  13. }

  这里是一个拦截接口,可以对它创建实现类。如果使用过Spring AOP,你就会发现笔者的定义和Spring AOP定义的消息是如此相近。

  代码清单:ProxyBeanFactory的getBean方法

  1. package com.ssm.chapter11.game;
  2.  
  3. public class ProxyBeanFactory {
  4. public static <T> T getBean(T obj, Interceptor interceptor) {
  5. return (T) ProxyBeanUtil.getBean(obj, interceptor);
  6. }
  7. }

  具体类ProxyBeanUtil的getBean方法的逻辑不需要去理会,因为这是笔者需要去完成的内容。但是作为读者,你要知道当使用了这个方法后,存在如下约定

  当一个对象通过ProxyBeanFactory的getBean方法定义后,拥有这样的约定。
  (1)Bean必须是一个实现了某一个接口的对象。
  (2)最先会执行拦截器的before方法。
  (3)其次执行Bean的方法(通过反射的形式)。
  (4)执行Bean方法时,无论是否产生异常,都会执行after方法。
  (5)执行Bean方法时,如果不产生异常,则执行afterReturning方法;如果产生异常,则执行afterThrowing方法。
  这个约定实际已经十分接近Spring AOP对我们的约定,所以这个约定十分重要,其流程如图所示。

读者的代码

  上面笔者给出了接口和获取Bean的方式,同时也给出了具体的约定,这个时候读者可以根据约定编写代码,比如打印一个角色信息。
  代码清单:RoleService接口

  1. package com.ssm.chapter11.game.service;
  2.  
  3. import com.ssm.chapter11.game.pojo.Role;
  4.  
  5. public interface RoleService {
  6. public void printRole(Role role);
  7. }

  代码清单:RoleServiceImpl

  1. package com.ssm.chapter11.game.service.impl;
  2.  
  3. import com.ssm.chapter11.game.pojo.Role;
  4. import com.ssm.chapter11.game.service.RoleService;
  5.  
  6. public class RoleServiceImpl implements RoleService {
  7.  
  8. // @Override
  9. public void printRole(Role role) {
  10. System.out.println("{id =" + role.getId() + ", roleName=" + role.getRoleName() + ", note=" + role.getNote() + "}");
  11. }
  12.  
  13. }

  代码清单:角色拦截器RoleInterceptor

  1. package com.ssm.chapter11.game.interceptor;
  2.  
  3. import com.ssm.chapter11.game.Interceptor;
  4.  
  5. public class RoleInterceptor implements Interceptor {
  6.  
  7. // @Override
  8. public void before(Object obj) {
  9. System.out.println("--before-准备打印角色信息");
  10. }
  11.  
  12. // @Override
  13. public void after(Object obj) {
  14. System.out.println("-after-已经完成角色信息的打印处理");
  15. }
  16.  
  17. // @Override
  18. public void afterReturning(Object obj) {
  19. System.out.println("-afterReturning-刚刚完成打印功能,一切正常。");
  20. }
  21.  
  22. // @Override
  23. public void afterThrowing(Object obj) {
  24. System.out.println("-afterThrowing-打印功能执行异常了,查看一下角色对象为空了吗?");
  25. }
  26.  
  27. }

  它编写了图中描述流程的各个方法,这个时候你可以清楚地知道代码将按照流程图的流程执行。注意,你并不需要知道笔者如何实现,你只需要知道我们之间的约定即可
  代码清单:测试约定流程

  1. package com.ssm.chapter11.game.main;
  2.  
  3. import com.ssm.chapter11.game.Interceptor;
  4. import com.ssm.chapter11.game.ProxyBeanFactory;
  5. import com.ssm.chapter11.game.interceptor.RoleInterceptor;
  6.  
  7. import com.ssm.chapter11.game.pojo.Role;
  8. import com.ssm.chapter11.game.service.RoleService;
  9. import com.ssm.chapter11.game.service.impl.RoleServiceImpl;
  10.  
  11. public class GameMain {
  12.  
  13. public static void main(String[] args) {
  14. RoleService roleService = new RoleServiceImpl();
  15. Interceptor interceptor = new RoleInterceptor();
  16. RoleService proxy = ProxyBeanFactory.getBean(roleService, interceptor);
  17. Role role = new Role(1L, "role_name_1", "role_note_1");
  18. proxy.printRole(role);
  19. System.out.println("############## 测试 afterthrowing方法###############");
  20. role = null;
  21. proxy.printRole(role);
  22. }
  23.  
  24. }

笔者的代码

  上面的代码都基于动态代理模式。
  下面展示通过JDK动态代理实现上述流程的代码,如代码清单所示。
  代码清单:使用动态代理实现流程

  1. package com.ssm.chapter11.game;
  2.  
  3. import java.lang.reflect.InvocationHandler;
  4. import java.lang.reflect.Method;
  5. import java.lang.reflect.Proxy;
  6.  
  7. class ProxyBeanUtil implements InvocationHandler {
  8.  
  9. //被代理对象
  10. private Object obj;
  11. // 拦截器
  12. private Interceptor interceptor = null;
  13.  
  14. /**
  15. * 获取动态代理对象.
  16. *
  17. * @param obj 被代理对象
  18. * @param interceptor 拦截器
  19. * @param aroundFlag 是否启用around方法
  20. * @return 动态代理对象
  21. */
  22. public static Object getBean(Object obj, Interceptor interceptor) {
  23. //使用当前类,作为代理方法,此时被代理对象执行方法的时候,会进入当前类的invoke方法里
  24. ProxyBeanUtil _this = new ProxyBeanUtil();
  25. //保存被代理对象
  26. _this.obj = obj;
  27. //保存拦截器
  28. _this.interceptor = interceptor;
  29. //生成代理对象,并绑定代理方法
  30. return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), _this);
  31. }
  32.  
  33. /**
  34. * 代理方法
  35. *
  36. * @param proxy 代理对象
  37. * @param method 当前调度方法
  38. * @param args 参数
  39. * @return 方法返回
  40. * @throws Throwable 异常
  41. */
  42. // @Override
  43. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  44. Object retObj = null;
  45. //是否产生异常
  46. boolean exceptionFlag = false;
  47. //before方法
  48. interceptor.before(obj);
  49. try {
  50. //反射原有方法
  51. retObj = method.invoke(obj, args);
  52. } catch (Exception ex) {
  53. exceptionFlag = true;
  54. } finally {
  55. //after方法
  56. interceptor.after(obj);
  57. }
  58. if (exceptionFlag) {
  59. //afterThrowing方法
  60. interceptor.afterThrowing(obj);
  61. } else {
  62. //afterReturning方法
  63. interceptor.afterReturning(obj);
  64. }
  65. return retObj;
  66. }
  67. }

  上面的代码使用了动态代理,由于这段代码的重要性,这里有必要讨论其实现过程。
  首先,通过getBean方法保存了被代理对象、拦截器(inter-ceptor)和参数(args),为之后的调用奠定了基础。然后,生成了JDK动态代理对象(proxy),同时绑定了ProxyBeanUtil的一个实例作为其代理类,这样当代理对象调用方法的时候,就会进入到ProxyBeanUtil实例的invoke方法中,于是焦点又到了invoke方法上。
  在invoke方法中,笔者将拦截器的方法按照流程图实现了一遍,其中设置了异常标志(exceptionFlag),通过这个标志就能判断反射原有对象方法的时候是否发生了异常,这就是读者的代码能够按照流程打印的原因。但是,由于动态代理和反射的代码会比较抽象,更多的时候大部分的框架只会告诉你流程图和具体的流程方法的配置,就像笔者之前只是给出约定而已,相信有心的读者已经明白这句话的意思了,这就是说Spring框架也是这样做的。 

 

spring 理解Spring AOP 一个简单的约定游戏的更多相关文章

  1. spring boot: @Entity @Repository一个简单的数据读存储读取

    spring boot: @Entity @Repository一个简单的数据读存储读取 创建了一个实体类. 如何持久化呢?1.使用@Entity进行实体类的持久化操作,当JPA检测到我们的实体类当中 ...

  2. 无聊的人用JS实现了一个简单的打地鼠游戏

    直入正题,用JS实现一个简单的打地鼠游戏 因为功能比较简单就直接裸奔JS了,先看看效果图,或者 在线玩玩 吧 如果点击颜色比较深的那个(俗称坏老鼠),将扣分50:如果点击颜色比较浅的那个(俗称好老鼠) ...

  3. Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏

    Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏 即使是如今,非常多初学游戏开发的同学.在谈到Unity的时候.依旧会觉得Unity仅仅能用于制作3D游戏的. 实际上.Unity在2013 ...

  4. 【模块化编程】理解requireJS-实现一个简单的模块加载器

    在前文中我们不止一次强调过模块化编程的重要性,以及其可以解决的问题: ① 解决单文件变量命名冲突问题 ② 解决前端多人协作问题 ③ 解决文件依赖问题 ④ 按需加载(这个说法其实很假了) ⑤ ..... ...

  5. 理解与模拟一个简单web服务器

    先简单说下几个概念,根据自己的理解,不正确请见谅. web服务器 首先要知道什么是web服务器,简单说web服务器就是可以使用HTTP传输协议与客户端进行通信的服务器.最初的web服务器只能用来处理静 ...

  6. 通过创建一个简单的骰子游戏来探究 Python

    在我的这系列的第一篇文章 中, 我已经讲解如何使用 Python 创建一个简单的.基于文本的骰子游戏.这次,我将展示如何使用 Python 模块 Pygame 来创建一个图形化游戏.它将需要几篇文章才 ...

  7. Spring IOC DI AOP 的简单理解及应用

    Spring两大特性:IOC 和AOP.IOC 控制反转,AOP 面向切面编程 spring 核心容器的主要组件时Bean工厂(BeanFactory) ,Bean 工厂使用控制反转模式来降低程序代码 ...

  8. spring boot:创建一个简单的web(maven web project)

    1.新建一个maven web project; 2.在pom.xml文件中添加相应的依赖包: 3.新建一个HelloController请求控制类: 4.编写index.jsp页面: 5.编写启动类 ...

  9. Spring学习笔记--声明一个简单的Bean

    spring依赖的maven dependencyhttp://mvnrepository.com/artifact/org.springframework 在pom.xml中添加如下依赖: < ...

随机推荐

  1. 物体检测方法(1) - YOLO 详解

    最近遇到一些卡证识别的检测问题,打算先把理论知识梳理一下,随后还会梳理一版代码注释. 以前的region+proposal来检测的框架,这一系列速度和精度不断提高,但是还是无法达到实时.存在的主要问题 ...

  2. 完美字符子串 单调队列预处理+DP线段树优化

    题意:有一个长度为n的字符串,每一位只会是p或j.你需要取出一个子串S(注意不是子序列),使得该子串不管是从左往右还是从右往左取,都保证每时每刻已取出的p的个数不小于j的个数.如果你的子串是最长的,那 ...

  3. Java编译器的优化

    public class Notice { public static void main(String[] args) { // 右侧20是一个int类型,但没有超过左侧数值范围,就是正确的 // ...

  4. SIGAI机器学习第二十一集 AdaBoost算法2

    讲授Boosting算法的原理,AdaBoost算法的基本概念,训练算法,与随机森林的比较,训练误差分析,广义加法模型,指数损失函数,训练算法的推导,弱分类器的选择,样本权重削减,实际应用. 大纲: ...

  5. 浏览器在线预览pdf、txt、office文件

    //使用文件预览的原因是:TMD微信浏览器屏蔽掉文件下载链接,只好折中使用文件在线预览功能//要点:1.office文件用微软的插件打开 http://view.officeapps.live.com ...

  6. TPS与QPS,以及GMV

    TPS是指每秒处理事务的个数,处理的载体可以是单台服务器,也可以是一个服务器集群. 例如:下单接口,一秒内,下单完成次数为1000,则下单接口总 tps = 1000,共有10台服务器提供下单服务,单 ...

  7. python模块之psutil

    一.模块安装 1.简介 psutil是一个跨平台库(http://pythonhosted.org/psutil/)能够轻松实现获取系统运行的进程和系统利用率(包括CPU.内存.磁盘.网络等)信息. ...

  8. Spark-Hadoop、Hive、Spark 之间是什么关系?

    作者:Xiaoyu Ma链接:https://www.zhihu.com/question/27974418/answer/38965760来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商 ...

  9. php单点登录SSO(Single Sign On)的解决思路

    一.什么是单点登录 解释:登录一个系统后,其它系统无需再次登录,即可进入. 二.举个例子: 你登录了淘宝,然后你进入天猫,发现你不用登录了.这时你要注意到,淘宝跟天猫可是完全不一样的域名. 你登录淘宝 ...

  10. [代码审计]PHP_Bugs题目总结(2)

    写的有点多了,上一篇放在一起显得有点臃肿,就再起一篇吧~ 迷路的老铁点这里:[代码审计]PHP_Bugs题目总结(1) 0x14 intval函数四舍五入 <?php if($_GET[id]) ...