关关雎鸠,在河之洲。窈窕淑女,君子好逑。

概述

AOPAspect Orient Programming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。 Spring AOP采用的是动态代理,在运行期间对业务方法进行增强,所以不会生成新类,Spring AOP提供了对JDK动态代理的支持以及CGLib的支持。本章我们不关注aop代理类的实现,我简单实现一个指定次序的链式调用。

实现链式调用的

MethodInterceptor定义拦截器链,MethodInvocation 递归进入下一个拦截器链中。类图如下:

MethodInterceptor

  1. public interface MethodInterceptor {
  2. Object invoke(MethodInvocation invocation) throws Throwable;
  3. }

MethodInvocation

  1. public interface MethodInvocation {
  2. Object proceed() throws Throwable;
  3. }

AbstractAspectJAdvice

抽象类,实现MethodInterceptor

  1. public abstract class AbstractAspectJAdvice implements MethodInterceptor{
  2. private Method adviceMethod;
  3. private Object adviceObject;
  4. public AbstractAspectJAdvice(Method adviceMethod, Object adviceObject) {
  5. this.adviceMethod = adviceMethod;
  6. this.adviceObject = adviceObject;
  7. }
  8. public Method getAdviceMethod() {
  9. return this.adviceMethod;
  10. }
  11. public void invokeAdviceMethod() throws Throwable {
  12. adviceMethod.invoke(adviceObject);
  13. }
  14. }

AspectJBeforeAdvice

前置通知

  1. public class AspectJBeforeAdvice extends AbstractAspectJAdvice {
  2. public AspectJBeforeAdvice(Method method, Object adviceObject) {
  3. super(method, adviceObject);
  4. }
  5. @Override
  6. public Object invoke(MethodInvocation invocation) throws Throwable{
  7. this.invokeAdviceMethod();
  8. Object o = invocation.proceed();
  9. return o;
  10. }
  11. }

AspectJAfterReturningAdvice

后置通知

  1. public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice {
  2. public AspectJAfterReturningAdvice(Method method, Object adviceObject) {
  3. super(method, adviceObject);
  4. }
  5. @Override
  6. public Object invoke(MethodInvocation invocation) throws Throwable{
  7. Object o = invocation.proceed();
  8. this.invokeAdviceMethod();
  9. return o;
  10. }
  11. }

ReflectiveMethodInvocation

实现MethodInvocationproceed()方法递归实现链式调用。

  1. public class ReflectiveMethodInvocation implements MethodInvocation {
  2. private final Object targetObject;
  3. private final Method targetMethod;
  4. private final List<MethodInterceptor> interceptorList;
  5. private int currentInterceptorIndex = -1;
  6. public ReflectiveMethodInvocation(Object targetObject, Method targetMethod, List<MethodInterceptor> interceptorList) {
  7. this.targetObject = targetObject;
  8. this.targetMethod = targetMethod;
  9. this.interceptorList = interceptorList;
  10. }
  11. @Override
  12. public Object proceed() throws Throwable {
  13. if (this.currentInterceptorIndex == this.interceptorList.size() - 1) {
  14. return invokeJoinPoint();
  15. }
  16. this.currentInterceptorIndex++;
  17. MethodInterceptor interceptor =
  18. this.interceptorList.get(this.currentInterceptorIndex);
  19. return interceptor.invoke(this);
  20. }
  21. private Object invokeJoinPoint() throws Throwable {
  22. return this.targetMethod.invoke(this.targetObject);
  23. }
  24. }

NioCoderService

模拟service

  1. public class NioCoderService {
  2. public void testAop() {
  3. System.out.println("http://niocoder.com/");
  4. }
  5. }

TransactionManager

模拟通知类

  1. public class TransactionManager {
  2. public void start() {
  3. System.out.println("start tx");
  4. }
  5. public void commit() {
  6. System.out.println("commit tx");
  7. }
  8. public void rollback() {
  9. System.out.println("rollback tx");
  10. }
  11. }

ReflectiveMethodInvocationTest

beforeAdvice->afterReturningAdvice

测试类,测试通知

  1. public class ReflectiveMethodInvocationTest {
  2. private AspectJBeforeAdvice beforeAdvice = null;
  3. private AspectJAfterReturningAdvice afterReturningAdvice = null;
  4. private NioCoderService nioCoderService;
  5. private TransactionManager tx;
  6. public void setUp() throws Exception {
  7. nioCoderService = new NioCoderService();
  8. tx = new TransactionManager();
  9. beforeAdvice = new AspectJBeforeAdvice(TransactionManager.class.getMethod("start"), tx);
  10. afterReturningAdvice = new AspectJAfterReturningAdvice(TransactionManager.class.getMethod("commit"), tx);
  11. }
  12. public void testMethodInvocation() throws Throwable {
  13. Method method = NioCoderService.class.getMethod("testAop");
  14. List<MethodInterceptor> interceptorList = new ArrayList<>();
  15. interceptorList.add(beforeAdvice);
  16. interceptorList.add(afterReturningAdvice);
  17. ReflectiveMethodInvocation mi = new ReflectiveMethodInvocation(nioCoderService, method, interceptorList);
  18. mi.proceed();
  19. }
  20. public static void main(String[] args) throws Throwable {
  21. ReflectiveMethodInvocationTest reflectiveMethodInvocationTest = new ReflectiveMethodInvocationTest();
  22. reflectiveMethodInvocationTest.setUp();
  23. reflectiveMethodInvocationTest.testMethodInvocation();
  24. }
  25. }

输出:

  1. start tx
  2. http://niocoder.com/
  3. commit tx
时序图 beforeAdvice->afterReturningAdvice

afterReturningAdvice->beforeAdvice

修改interceptorList的顺序

  1. public void testMethodInvocation() throws Throwable {
  2. Method method = NioCoderService.class.getMethod("testAop");
  3. List<MethodInterceptor> interceptorList = new ArrayList<>();
  4. interceptorList.add(afterReturningAdvice);
  5. interceptorList.add(beforeAdvice);
  6. ReflectiveMethodInvocation mi = new ReflectiveMethodInvocation(nioCoderService, method, interceptorList);
  7. mi.proceed();
  8. }

输出:

  1. start tx
  2. http://niocoder.com/
  3. commit tx
时序图 afterReturningAdvice->beforeAdvice

代码下载

代码下载

spring aop 之链式调用的更多相关文章

  1. 仿jQuery之链式调用

    链式调用的形式其实就是对象调用一连串的方法.为什么能连续调用这么多的方法?因为调用方法返回调用的对象,于是乎就可以一如既往,一往无前地调用下去.链式调用的原理就是在方法中返回执行上下文this,每次调 ...

  2. Javasript设计模式之链式调用

    写过jquery的可能都知道,jquery里面可以很方便的使用以下代码: // 不使用链式调用 const element = $(ele); element.addClass('red'); ele ...

  3. Jquery复习(三)之链式调用

    通过 jQuery,可以把动作/方法链接在一起. Chaining 允许我们在一条语句中运行多个 jQuery 方法(在相同的元素上). jQuery 方法链接 直到现在,我们都是一次写一条 jQue ...

  4. jquery之链式调用,层级菜单

    一. 链式调用的含义 jquery对象的方法会在执行完后返回这个jquery对象,所有jquery对象的方法可以连起来写: $('#div1') // id为div1的元素 .children('ul ...

  5. Spring AOP调用本类方法为什么没有生效

    首先请思考一下以下代码执行的结果: LogAop.java //声明一个AOP拦截service包下的所有方法@Aspectpublic class LogAop { @Around("ex ...

  6. Spring技术内幕:Spring AOP的实现原理(一)

    一.SpringAOP的概述 1.AOP概念 AOP是Aspect-Oriented Programming(面向切面编程)的简称.维基百科的解释例如以下: Aspect是一种新的模块化机制,用来描写 ...

  7. Spring AOP 问与答

    AOP的实现有哪些 AOP常见的实现有: Spring AOP Aspectj Guice AOP Jboss AOP 等 AOP Alliance 是什么, 为什么Spring AOP, G UIC ...

  8. Spring AOP 概述

    1. AOP的概念 AOP 是Aspect-Oriented Programming(面向方面编程或者面向切面)的简称,维基百科对其解释如下: Aspect是一种新的模块化机制,用来描述分散在对象.类 ...

  9. Spring技术内幕:Spring AOP的实现原理(三)

    生成SingleTon代理对象在getSingleTonInstance方法中完毕,这种方法时ProxyFactoryBean生成AopProxy对象的入口.代理对象会封装对target目标对象的调用 ...

随机推荐

  1. (一)c#Winform自定义控件-基类控件

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...

  2. Nginx 1.15.5: 405 Not Allowed

    0x00 事件 在做一个业务跳转时,遇到这个错误 405 Not Allowed,找了挺多资料,多数解决方案是让在 nginx 配置文件中直接添加 error_page 405 =200 $uri; ...

  3. Mysql的B+ Tree索引

    为什么要使用索引? 最简单的方式实现数据查询:全表扫描,即将整张表的数据全部或者分批次加载进内存,由于存储的最小单位是块或者页,它们是由多行数据组成,然后逐块逐块或者逐页逐页地查找,这样查找的速度非常 ...

  4. ansible之变量

    一.常用系统变量 1. loop   #表示循环,去读循环体里的变量固定使用{{item}},item是个字典对象item.key=value,例如如下playbook内容: --- - name: ...

  5. 对微软的敌视何时休? 从一篇语言评论文章对C#的评价说起

    看到一篇公众号文章<2020年什么编程语言最受欢迎,待遇最高?>,其中对C#的描述如下: 点击阅读原文,看到这是一篇翻译文章:https://codinginfinite.com/top- ...

  6. 危险的Hystrix线程池

    本文介绍Hystrix线程池的工作原理和参数配置,指出存在的问题并提供规避方案,阅读本文需要对Hystrix有一定的了解. 文本讨论的内容,基于hystrix 1.5.18: <dependen ...

  7. MySQL多表关联数据同时删除

    MySQL多表关联时的多表删除: DELETE t1, t2FROM    t1LEFT JOIN t2 ON t1.id = t2.idWHERE    t1.id = 25

  8. css3弹性盒子 flex布局

    CSS3 弹性盒 1.display:flex 说明: 设置为弹性盒(父元素添加) 2.flex-direction(主轴排列方式) 说明: 顺序指定了弹性子元素在父容器中的位置 row 默认在一行内 ...

  9. java高并发系列 - 第31天:获取线程执行结果,这6种方法你都知道?

    这是java高并发系列第31篇. 环境:jdk1.8. java高并发系列已经学了不少东西了,本篇文章,我们用前面学的知识来实现一个需求: 在一个线程中需要获取其他线程的执行结果,能想到几种方式?各有 ...

  10. Scrum 工件: 速度图和燃尽图

    速度图 Velocity用于衡量scrum团队持续提供业务价值的速度,可以采用历史估算的方法,衡量一个又一个sprint的速度.团队通过跟踪完成达到自己团队完成标准的故事点的数量,就可以基于相对点值对 ...