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

概述

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

代码下载

代码下载

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. 【win】【qt5安装】【qt5.5.1安装及第一个示例make错误】

    [前言] 昨天按照需求将qt程序从linux系统移植到win上使用(其实有点缪论了,本人linux用的中标麒麟系统对于发布发布系统版本麒麟(注:以下用麒麟代替中标麒麟,什么银河麒麟,优麒麟的,我现在只 ...

  2. python练习题-1

    1.输出正方形 x=input("请输入:") x=int(x) for i in range(0,x): if (i==0) or (i==x-1): print("* ...

  3. 容易上手搭建vue2.0开发环境

    第一步:安装node 前端开发框架和环境都是需要 Node.js ,先安装node.js开发环境,vue的运行是要依赖于node的npm的管理工具来实现,下载https://nodejs.org/en ...

  4. git:将代码提交到远程仓库(码云)

    初始化 进入一个任意的文件夹(如D:\aqin_test1\) git init # 初始化,让git将这个文件夹管理起来 git add . # 收集此文件夹下的所有文件 git config -- ...

  5. 深入解析Mysql中事务的四大隔离级别及其所解决的读现象

    本文详细介绍四种事务隔离级别,并通过举例的方式说明不同的级别能解决什么样的读现象.并且介绍了在关系型数据库中不同的隔离级别的实现原理. 在DBMS中,事务保证了一个操作序列可以全部都执行或者全部都不执 ...

  6. 如何彻底禁用 werfalut.exe

    在程序中调用 控制台程序 的时候,一旦出现控制台出现 crash 往往会弹出 werfault 窗口, 这样往往会锁死线程,导致程序无法继续运行. 那如何禁止 werfault 窗口的弹出呢? 在 s ...

  7. 《Java 8 in Action》Chapter 5:使用流

    流让你从外部迭代转向内部迭代,for循环显示迭代不用再写了,流内部管理对集合数据的迭代.这种处理数据的方式很有用,因为你让Stream API管理如何处理数据.这样Stream API就可以在背后进行 ...

  8. python 37 同步、异步调用

    目录 1. 阻塞与非阻塞 2. 同步与异步 2.1 异步调用 2.2 同步调用 2.3 异步调用回收的第一种方式 3. 异步调用+回调函数 3.1 requests模块 3.2 异步调用回收的第二种方 ...

  9. [The Preliminary Contest for ICPC Asia Nanjing 2019] A-The beautiful values of the palace(二维偏序+思维)

    >传送门< 前言 这题比赛的时候觉得能做,硬是怼了一个半小时,最后还是放弃了.开始想到用二维前缀和,结果$n\leq 10^{6}$时间和空间上都爆了,没有办法.赛后看题解用树状数组,一看 ...

  10. 猫眼电影和电影天堂数据csv和mysql存储

    字符串常用方法 # 去掉左右空格 'hello world'.strip() # 'hello world' # 按指定字符切割 'hello world'.split(' ') # ['hello' ...