AOP操作是我们日常开发经常使用到的操作,例如都会用到的spring事务管理.今天我们通过一个demo实现对一个类的某一个方法进行前置和后置的增强.

//被增强类
public class PetStoreService {
//被增强方法
public void placeOrder(){
System.out.println("place order");
}
}
//增强类
public class TransactionManager { //前置方法
public void start() {
System.out.println("start");
} //后置方法
public void end() {
System.out.println("end");
}
}

我们要做的就是在PetStoreService 中的placeOrder()执行前和执行后分别执行TransactionManager 中的start()和end()方法.下面我们将抽象出一个通知接口

//通知
public interface Advice {
//执行增强方法
public void invoke(InterceptorChain chain);
}

两个实现类,分别来执行start()和end()方法

//前置增强
public class BeforeAdvice implements Advice {
//增强方法所属实例对象
private Object object;
//增强方法
private Method method;
//增强方法的参数
private Object[] arguments; public BeforeAdvice(Object object, Method method, Object[] arguments) {
this.object = object;
this.method = method;
this.arguments = arguments;
} //织入方法
public void invoke(InterceptorChain chain) {
try {
//执行增强方法
method.invoke(object, arguments);
//返回
chain.proceed();
} catch (Exception e) {
System.out.println("执行after方法失败!!!!");
}
}
}
//后置增强
public class AfterAdvice implements Advice {
//增强方法所属实例对象
private Object object;
//增强方法
private Method method;
//增强方法的参数
private Object[] arguments; public AfterAdvice(Object object, Method method, Object[] arguments) {
this.object = object;
this.method = method;
this.arguments = arguments;
} //织入方法
public void invoke(InterceptorChain chain) {
try {
//返回
chain.proceed();
//执行增强方法
method.invoke(object, arguments);
} catch (Exception e) {
System.out.println("执行after方法失败!!!!");
}
}
}

两个方法中的构造子相同,都是给出通知类所需要的参数,而invoke()则是使用反射执行增强方法.

需要注意的是invoke()方法的参数,是一个拦截器链,两个方法都在执行自身Method方法前或者后执行了拦截器链中的方法.

下面是拦截器链

public class InterceptorChain {

    //拦截器链
private List<Advice> adviceList; //需要增强的对象
private Object object; //需要增强的方法
private Method method; //当前需要执行方法的参数
private Object[] arguments; //当前要执行的拦截器指针
private int pointer = -1; //构造子
InterceptorChain(Object obj, Method method, Object[] arguments) {
this.object = obj;
this.method = method;
this.arguments = arguments;
this.adviceList = new ArrayList<Advice>();
} //执行拦截器链
public void proceed() {
//如果当前指针指向拦截器末尾则执行自身得方法
if (this.pointer == adviceList.size() - 1) {
invoke();
return;
} //指针+1
pointer++; //获取需要执行的拦截器
Advice advice = this.adviceList.get(pointer); //执行了拦截器
advice.invoke(this);
} //执行原方法
public void invoke() {
try {
method.invoke(object, arguments);
} catch (Exception e) {
System.out.println("执行原有方法失败!!!");
}
} //增加拦截器 public void addAdvice(Advice advice) {
this.adviceList.add(advice);
}
}

这是一个核心类,其中的关键在于,客户端将把增强类添加到拦截器链中,在拦截器链中有一个指针pointer用来指向即将执行的增强方法.

下面是客户端调用

public class Main {
public static void main(String[] args) throws Exception {
//需要增强的对象
PetStoreService petStoreService = new PetStoreService();
//增强
TransactionManager transactionManager = new TransactionManager(); //创建拦截器
InterceptorChain interceptorChain = new InterceptorChain(petStoreService, PetStoreService.class.getMethod("placeOrder"), new Object[0]); //增加拦截器链
interceptorChain.addAdvice(new BeforeAdvice(transactionManager, TransactionManager.class.getMethod("start"), new Object[0])); //增加拦截器链
interceptorChain.addAdvice(new AfterAdvice(transactionManager, TransactionManager.class.getMethod("end"), new Object[0])); //执行拦截器方法
interceptorChain.proceed();
}
}

我们分别创建需要增强的对象,还有增强对象.并把增强对象中的增强方法添加到拦截器链中.最终我们实现了,按照顺序执行完了拦截器链中的方法.感兴趣的同学可以debug试试看.

两个advice中调用拦截器的proceed()方法顺序,不一样的话,会有不同的结果哦.

实现简单的AOP前置后置增强的更多相关文章

  1. Spring aop——前置增强和后置增强 使用注解Aspect和非侵入式配置

    AspectJ是一个面向切面的框架,它扩展了java语言,定义了AOP语法,能够在编译期提供代码的织入,所以它有一个专门的编译器用来生成遵守字节码字节编码规范的Class文件 确保使用jdk为5.0以 ...

  2. AOP 环绕通知 集成了前置 后置 返回通知等功能

    AOP 环绕通知 集成了前置 后置 返回通知等功能

  3. Spring 中AOP及前后置增强案例

    1.AOP面向切面编程 面向切面编程的本质:面向切面编程,指扩展功能不修改源代码,将功能代码从业务逻辑代码中分离出来.  1主要功能:日志记录,性能统计,安全控制,事务处理,异常处理等等.  2主要意 ...

  4. Spring Bean前置后置处理器的使用

    Spirng中BeanPostProcessor和InstantiationAwareBeanPostProcessorAdapter两个接口都可以实现对bean前置后置处理的效果,那这次先讲解一下B ...

  5. spring 切面 前置后置通知 环绕通知demo

    环绕通知: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http:// ...

  6. pytest_前置后置

    今天总结下pytest,pytest简直就是python自动化中的高富帅,各种操作,哈哈 这次总结主要涉及到了以下几点: 1.unittest中的setUp.tearDown.setUpClass.t ...

  7. unittest的前置后置,pytest的fixture和共享机制conftest.py

    Unittest setUp/tearDown setUp当中得到的变量,用self.xxx = value传递给测试用例 setUpClass/tearDownClass setupClass当中得 ...

  8. Spring -- aop(面向切面编程),前置&后置&环绕&抛异常通知,引入通知,自动代理

    1.概要 aop:面向方面编程.不改变源代码,还为类增加新的功能.(代理) 切面:实现的交叉功能. 通知:切面的实际实现(通知要做什么,怎么做). 连接点:应用程序执行过程期间,可以插入切面的地点. ...

  9. C: printf参数执行顺序与前置后置自增自减的影响

    起源: 今天在了解副作用side-effect的过程中,看到了下面的网页,把我带到了由printf引起的一系列问题,纠结了一整天,勉强弄懂. 第一个代码没什么好解释的.而第二个printf(" ...

随机推荐

  1. 设计模式之(十三)外观模式(Facade)

    外观模式思想 历史上牛人中成功逆袭,实现人生辉煌的人很多,这群人最耀眼的无疑是明太祖朱元璋,从一个放牛讨饭的最低层小屌丝逆袭到人类权力顶峰开国皇帝,确实是我等膜拜的对象.在发不断的发展过程中,其实就在 ...

  2. 记录下vue keep-alive IOS下无法保存滚动scroll位置的问题

    最近 做的项目,遇到了一点小麻烦,就是我一个页面A页面是加载 列表数据 ,B页面是展示详细信息的.A进去B时,缓存A页面. 效果 做出来 后,缓存是缓存数据 了,但是当我A页面的列表数据 好多,要滚动 ...

  3. 记录Mac OS下编译Thrift库

    方法一:brew管理工具安装Homebrew是Mac开发包管理工具,类似于Linux的apt-get之类的,实它相当于开发软件界的 Appstore.借助该管理工具,可以自动化地安装软件包,它会自动安 ...

  4. Windows 10 蓝牙管理页面"添加蓝牙或其他设备"选项点击无响应的解决方案

    解决方案1(简单,但不解决根本问题): 通过"控制面板→设备和打印机→添加设备"进行添加. 解决方案2: 造成这种现象的原因应该是因为启用了 Administrator 账户,在其 ...

  5. 是否注意过isEmpty 和 isBlank 区别?

    isEmpty 和 isBlank 区别 org.apache.commons.lang.StringUtils 类提供了 String 的常用操作,最为常用的判空有如下两种 isEmpty(Stri ...

  6. Shell 编程 免交互 expect

    本篇主要写一些shell脚本免交互expect的使用. 概述 Expect是建立在tcl基础上的一个工具,Expect 是用来进行自动化控制和测试的工具.主要解决shell脚本中不可交互的问题. 安装 ...

  7. 使用Deployment控制器创建Pods并使Service发布到外网可访问

    由于NFS支持节点共同读取及写入,所以可使用Deployment控制器创建多个Pod,并且每一个Pod都共享同一个目录 k8s-master kubnet@hadoop2 volumes]$ vim ...

  8. python 的 encode 、decode、字节串、字符串

    一.摆个图 DJ  DJ  DJ   Decode. J 解码 首先得知道字符串有哪些编码格式,至于为什么会有这么多的编码格式,以后再了解更新. 1.ASCII 占1个字节,只支持英文 2.GB231 ...

  9. 小样本学习(few-shot learning)在文本分类中的应用

    1,概述 目前有效的文本分类方法都是建立在具有大量的标签数据下的有监督学习,例如常见的textcnn,textrnn等,但是在很多场景下的文本分类是无法提供这么多训练数据的,比如对话场景下的意图识别, ...

  10. 第05节-BLE协议物理层(PHY)

    对于软件的人来说,物理层关注的内容会少一点.在前面的博客中,我们以快递员类比物理层,对于快递员来说,道路千万条,这条不通换另外一条.对于物理层来说也是一样的,它有很多频率,这个频率有冲突了,将会切到另 ...