spring aop之链式调用的实现

 更新时间:2019年02月20日 10:18:19   作者:niocoder  
这篇文章主要介绍了spring aop之链式调用的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

概述

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

实现链式调用的

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

MethodInterceptor

public interface MethodInterceptor {

  Object invoke(MethodInvocation invocation) throws Throwable;
}

MethodInvocation

public interface MethodInvocation {

  Object proceed() throws Throwable;
}

AbstractAspectJAdvice

抽象类,实现MethodInterceptor

public abstract class AbstractAspectJAdvice implements MethodInterceptor{

  private Method adviceMethod;

  private Object adviceObject;

  public AbstractAspectJAdvice(Method adviceMethod, Object adviceObject) {
    this.adviceMethod = adviceMethod;
    this.adviceObject = adviceObject;
  }

  public Method getAdviceMethod() {
    return this.adviceMethod;
  }

  public void invokeAdviceMethod() throws Throwable {
    adviceMethod.invoke(adviceObject);
  }
}

AspectJBeforeAdvice

前置通知

public class AspectJBeforeAdvice extends AbstractAspectJAdvice {

  public AspectJBeforeAdvice(Method method, Object adviceObject) {
    super(method, adviceObject);
  }

  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable{
    this.invokeAdviceMethod();
    Object o = invocation.proceed();
    return o;
  }
}

AspectJAfterReturningAdvice

后置通知

public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice {

  public AspectJAfterReturningAdvice(Method method, Object adviceObject) {
    super(method, adviceObject);
  }

  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable{
    Object o = invocation.proceed();
    this.invokeAdviceMethod();
    return o;
  }
}

ReflectiveMethodInvocation

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

public class ReflectiveMethodInvocation implements MethodInvocation {

  private final Object targetObject;

  private final Method targetMethod;

  private final List<MethodInterceptor> interceptorList;

  private int currentInterceptorIndex = -1;

  public ReflectiveMethodInvocation(Object targetObject, Method targetMethod, List<MethodInterceptor> interceptorList) {
    this.targetObject = targetObject;
    this.targetMethod = targetMethod;
    this.interceptorList = interceptorList;
  }

  @Override
  public Object proceed() throws Throwable {

    if (this.currentInterceptorIndex == this.interceptorList.size() - 1) {
      return invokeJoinPoint();
    }

    this.currentInterceptorIndex++;

    MethodInterceptor interceptor =
        this.interceptorList.get(this.currentInterceptorIndex);
    return interceptor.invoke(this);
  }

  private Object invokeJoinPoint() throws Throwable {

    return this.targetMethod.invoke(this.targetObject);
  }
}

NioCoderService

模拟service

public class NioCoderService {

  public void testAop() {
    System.out.println("http://niocoder.com/");
  }
}

TransactionManager

模拟通知类

public class TransactionManager {
  public void start() {
    System.out.println("start tx");
  }

  public void commit() {
    System.out.println("commit tx");
  }

  public void rollback() {
    System.out.println("rollback tx");
  }

}

ReflectiveMethodInvocationTest

beforeAdvice->afterReturningAdvice

测试类,测试通知

public class ReflectiveMethodInvocationTest {

  private AspectJBeforeAdvice beforeAdvice = null;

  private AspectJAfterReturningAdvice afterReturningAdvice = null;

  private NioCoderService nioCoderService;

  private TransactionManager tx;

  public void setUp() throws Exception {
    nioCoderService = new NioCoderService();
    tx = new TransactionManager();
    beforeAdvice = new AspectJBeforeAdvice(TransactionManager.class.getMethod("start"), tx);
    afterReturningAdvice = new AspectJAfterReturningAdvice(TransactionManager.class.getMethod("commit"), tx);
  }

  public void testMethodInvocation() throws Throwable {
    Method method = NioCoderService.class.getMethod("testAop");
    List<MethodInterceptor> interceptorList = new ArrayList<>();
    interceptorList.add(beforeAdvice);
    interceptorList.add(afterReturningAdvice);    

    ReflectiveMethodInvocation mi = new ReflectiveMethodInvocation(nioCoderService, method, interceptorList);

    mi.proceed();
  }


  public static void main(String[] args) throws Throwable {
    ReflectiveMethodInvocationTest reflectiveMethodInvocationTest = new ReflectiveMethodInvocationTest();
    reflectiveMethodInvocationTest.setUp();
    reflectiveMethodInvocationTest.testMethodInvocation();
  }
}

输出:

start tx
http://niocoder.com/
commit tx

时序图 beforeAdvice->afterReturningAdvice

afterReturningAdvice->beforeAdvice

修改interceptorList的顺序

public void testMethodInvocation() throws Throwable {
    Method method = NioCoderService.class.getMethod("testAop");
    List<MethodInterceptor> interceptorList = new ArrayList<>();
    interceptorList.add(afterReturningAdvice);
     interceptorList.add(beforeAdvice);

    ReflectiveMethodInvocation mi = new ReflectiveMethodInvocation(nioCoderService, method, interceptorList);

    mi.proceed();
  }

输出:

start tx
http://niocoder.com/
commit tx

时序图 afterReturningAdvice->beforeAdvice

代码下载

github:https://github.com/longfeizheng/data-structure-java/blob/master/src/main/java/cn/merryyou/aop

代码下载

github:https://github.com/longfeizheng/data-structure-java

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Java获取环境变量(System.getenv)的方法

    Java获取环境变量(System.getenv)的方法

    本文主要介绍了Java获取环境变量(System.getenv)的方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • 深入理解Java设计模式之外观模式

    深入理解Java设计模式之外观模式

    这篇文章主要介绍了JAVA设计模式之外观模式的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下
    2021-11-11
  • SpringBoot使用PropertiesLauncher加载外部jar包

    SpringBoot使用PropertiesLauncher加载外部jar包

    这篇文章主要介绍了SpringBoot使用PropertiesLauncher加载外部jar包,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • Java synchronized线程交替运行实现过程详解

    Java synchronized线程交替运行实现过程详解

    这篇文章主要介绍了Java synchronized线程交替运行实现过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11
  • springboot动态调整日志级别的操作大全

    springboot动态调整日志级别的操作大全

    这篇文章主要介绍了springboot动态调整日志级别的方法,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-10-10
  • MyBatis中特殊符号的转义

    MyBatis中特殊符号的转义

    编写SQL中会用到<,>,,>= 等,但是在mybatis中不可以这么写,与xml文件的元素冲突,所以需要转义,本文主要介绍了MyBatis中特殊符号的转义,主要介绍了两种转义方式,感兴趣的可以了解一下
    2024-01-01
  • 浅谈Spring 重定向指南

    浅谈Spring 重定向指南

    本篇文章主要介绍了浅谈Spring 重定向指南,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • idea每次新打开的项目窗口maven都要重新设置问题

    idea每次新打开的项目窗口maven都要重新设置问题

    这篇文章主要介绍了idea每次新打开的项目窗口maven都要重新设置问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • Spring的定时任务@Scheduled源码详解

    Spring的定时任务@Scheduled源码详解

    这篇文章主要介绍了Spring的定时任务@Scheduled源码详解,@Scheduled注解是包org.springframework.scheduling.annotation中的一个注解,主要是用来开启定时任务,本文提供了部分实现代码与思路,需要的朋友可以参考下
    2023-09-09
  • Java快速生成PDF文档的实例代码

    Java快速生成PDF文档的实例代码

    在如今数字化时代,越来越多的人使用PDF文档进行信息传递和共享,而使用Java生成PDF文档也成为了一个非常重要的技能,所以本文我们将为您介绍如何使用Java快速生成PDF文档,需要的朋友可以参考下
    2023-09-09

最新评论