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目标对象的调用 ...
随机推荐
- MYSQL 入门配置
1.下载 MYSQL官网 2.目录结构图基本如下 3.运行CMD(管理员权限),进入MYSQL目录下面的bin目录 4.执行 mysqld install 5.执行 net start mysql 6 ...
- JDK集合面试20问
1. HashMap的内部实现原理是什么? HashMap内部实现原理是数组+链表,通过散列算法将key值散列到数组中,如果到相同的位置,则通过拉链法解决散列冲突.在JDK8中新增了红黑树结构,当Ha ...
- 这些用来审计 Kubernetes RBAC 策略的方法你都见过吗?
原文链接:这些用来审计 Kubernetes RBAC 策略的方法你都见过吗? 认证与授权对任何安全系统来说都至关重要,Kubernetes 也不例外.即使我们不是安全工作人员,也需要了解我们的 Ku ...
- Java基础及JavaWEB以及SSM框架学习笔记Xmind版
Java基础及JavaWEB以及SSM框架学习笔记Xmind版 转行做程序员也1年多了,最近开始整理以前学习过程中记录的笔记,以及一些容易犯错的内容.现在分享给网友们.笔记共三部分. JavaSE 目 ...
- 2015-11-13 linux基础笔记
1.安装linux 使用光盘,版本CENSOS6.6 2.命令过长请使用\ 后enter键换行转义 直到不需要转义后回车运行 3.linux 大小写敏感 4.显示terminal 输出语言 ec ...
- idea 打包失败心得一
- Vue+ElementUI项目使用webpack输出MPA
目录 Vue+ElementUI项目使用webpack输出MPA 一. 需求分析 二. 原方案分析 三. 多页面改造3步走 四. 小结 Vue+ElementUI项目使用webpack输出MPA 示例 ...
- ESXi安装报错,No network adapters were detected...
转载请在文章开头附上原文链接地址:https://www.cnblogs.com/Sunzz/p/11438066.html 报错内容 No network adapters No Network a ...
- 【阿里云IoT+YF3300】5. Alink物模型之服务下发
名词解释: 服务:设备的功能模型之一,设备可被外部调用的能力或方法,可设置输入参数和输出参数.相比于属性,服务可通过一条指令实现更复杂的业务逻辑,如执行某项特定的任务. -摘自阿里云物联网产品文 ...
- node.js常用的全局成员和对象
一般可以直接调用的对象,我们称之为全局对象: 一下对象都加了console.log(),以在运行环境中的显示效果为标准 //包含文件名称的全路径: console.log(_filename); ...