spring aop 之链式调用
关关雎鸠,在河之洲。窈窕淑女,君子好逑。

概述
AOP(Aspect 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
实现MethodInvocation,proceed()方法递归实现链式调用。
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
代码下载
spring aop 之链式调用的更多相关文章
- 仿jQuery之链式调用
链式调用的形式其实就是对象调用一连串的方法.为什么能连续调用这么多的方法?因为调用方法返回调用的对象,于是乎就可以一如既往,一往无前地调用下去.链式调用的原理就是在方法中返回执行上下文this,每次调 ...
- Javasript设计模式之链式调用
写过jquery的可能都知道,jquery里面可以很方便的使用以下代码: // 不使用链式调用 const element = $(ele); element.addClass('red'); ele ...
- Jquery复习(三)之链式调用
通过 jQuery,可以把动作/方法链接在一起. Chaining 允许我们在一条语句中运行多个 jQuery 方法(在相同的元素上). jQuery 方法链接 直到现在,我们都是一次写一条 jQue ...
- jquery之链式调用,层级菜单
一. 链式调用的含义 jquery对象的方法会在执行完后返回这个jquery对象,所有jquery对象的方法可以连起来写: $('#div1') // id为div1的元素 .children('ul ...
- Spring AOP调用本类方法为什么没有生效
首先请思考一下以下代码执行的结果: LogAop.java //声明一个AOP拦截service包下的所有方法@Aspectpublic class LogAop { @Around("ex ...
- Spring技术内幕:Spring AOP的实现原理(一)
一.SpringAOP的概述 1.AOP概念 AOP是Aspect-Oriented Programming(面向切面编程)的简称.维基百科的解释例如以下: Aspect是一种新的模块化机制,用来描写 ...
- Spring AOP 问与答
AOP的实现有哪些 AOP常见的实现有: Spring AOP Aspectj Guice AOP Jboss AOP 等 AOP Alliance 是什么, 为什么Spring AOP, G UIC ...
- Spring AOP 概述
1. AOP的概念 AOP 是Aspect-Oriented Programming(面向方面编程或者面向切面)的简称,维基百科对其解释如下: Aspect是一种新的模块化机制,用来描述分散在对象.类 ...
- Spring技术内幕:Spring AOP的实现原理(三)
生成SingleTon代理对象在getSingleTonInstance方法中完毕,这种方法时ProxyFactoryBean生成AopProxy对象的入口.代理对象会封装对target目标对象的调用 ...
随机推荐
- 从零开始实现ASP.NET Core MVC的插件式开发(四) - 插件安装
标题:从零开始实现ASP.NET Core MVC的插件式开发(四) - 插件安装 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p/11260750. ...
- (二十三)c#Winform自定义控件-等待窗体
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...
- 四六级成绩还可以这样查?Python助你装B一步到位!!!
昨天有很多同学在朋友圈秀六级成绩 一个个都如(sang)此(jin)优(tian)秀(liang) 当然也有悲催的哥们 对于上面这位老弟 我只能说:骚呢,兄弟 这种事都能赶上,必须点赞 一.需求分析 ...
- python + selenium webdriver 复合型css样式的元素定位方法
<div class="header layout clearfix"></div> 当元素没有id,没有name,没有任何,只有一个class的时候,应该 ...
- Java 从入门到进阶之路(二)
之前的文章我们介绍了一下用 IDEA 编辑器创建一个 Java 项目并输出 HelloWorld,本章我们来看一下 Java 中的变量和基本数据类型. 在这之前我们先来看一下 Java 中的关键字,这 ...
- Mongodb最基础入门教程
Mongodb最基础入门教程 如果想了解一下redis的入门教程,可以去看一下我的上一篇博客 Mongodb的安装大家可以参考一下其他博主的博客,这里我就不做介绍了.不过值得注意的是,在Linux ...
- 一文道尽JavaScript 20年的发展史
作者介绍:Andrew Montalenti是Parse.ly的CTO, 一个长期的Python爱好者,以及初创公司和其他项目的创始人. 原文链接:https://amontalenti.com/ ...
- POJ 1015 陪审团问题
题意略. 思路: 这个题目开始我本来打算用个二维dp,令dp[ i ][ j ]为考虑前i个人,有j个名额的时候,我所能获取的最小差,后来发现不好转移.因为dp[ i ][ j ]有可能是+2, 也有 ...
- 分布式任务调度框架 Azkaban —— Flow 1.0 的使用
一.简介 Azkaban 主要通过界面上传配置文件来进行任务的调度.它有两个重要的概念: Job: 你需要执行的调度任务: Flow:一个获取多个 Job 及它们之间的依赖关系所组成的图表叫做 Flo ...
- Spring框架介绍及使用(转载)
原文链接 Spring框架—控制反转(IOC) 1 Spring框架概述1.1 什么是SpringSpring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod ...