实现简单的AOP前置后置增强
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前置后置增强的更多相关文章
- Spring aop——前置增强和后置增强 使用注解Aspect和非侵入式配置
AspectJ是一个面向切面的框架,它扩展了java语言,定义了AOP语法,能够在编译期提供代码的织入,所以它有一个专门的编译器用来生成遵守字节码字节编码规范的Class文件 确保使用jdk为5.0以 ...
- AOP 环绕通知 集成了前置 后置 返回通知等功能
AOP 环绕通知 集成了前置 后置 返回通知等功能
- Spring 中AOP及前后置增强案例
1.AOP面向切面编程 面向切面编程的本质:面向切面编程,指扩展功能不修改源代码,将功能代码从业务逻辑代码中分离出来. 1主要功能:日志记录,性能统计,安全控制,事务处理,异常处理等等. 2主要意 ...
- Spring Bean前置后置处理器的使用
Spirng中BeanPostProcessor和InstantiationAwareBeanPostProcessorAdapter两个接口都可以实现对bean前置后置处理的效果,那这次先讲解一下B ...
- spring 切面 前置后置通知 环绕通知demo
环绕通知: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http:// ...
- pytest_前置后置
今天总结下pytest,pytest简直就是python自动化中的高富帅,各种操作,哈哈 这次总结主要涉及到了以下几点: 1.unittest中的setUp.tearDown.setUpClass.t ...
- unittest的前置后置,pytest的fixture和共享机制conftest.py
Unittest setUp/tearDown setUp当中得到的变量,用self.xxx = value传递给测试用例 setUpClass/tearDownClass setupClass当中得 ...
- Spring -- aop(面向切面编程),前置&后置&环绕&抛异常通知,引入通知,自动代理
1.概要 aop:面向方面编程.不改变源代码,还为类增加新的功能.(代理) 切面:实现的交叉功能. 通知:切面的实际实现(通知要做什么,怎么做). 连接点:应用程序执行过程期间,可以插入切面的地点. ...
- C: printf参数执行顺序与前置后置自增自减的影响
起源: 今天在了解副作用side-effect的过程中,看到了下面的网页,把我带到了由printf引起的一系列问题,纠结了一整天,勉强弄懂. 第一个代码没什么好解释的.而第二个printf(" ...
随机推荐
- 史上最全的音视频SDK包分享给大家
史上最全的音视频SDK包分享给大家 概述一下SDK功能: 项目 详情视频通信 支持多种分辨率的视频通信语音通信 提供语音通信,可支持高清宽带语音动态创建房间 可以根据需要,随时创建房间H5 支持 ...
- web.xml——安全性框架配置文件
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://w ...
- Spring @Import注解源码解析
简介 Spring 3.0之前,创建Bean可以通过xml配置文件与扫描特定包下面的类来将类注入到Spring IOC容器内.而在Spring 3.0之后提供了JavaConfig的方式,也就是将IO ...
- 安装ceres-solver win10遇到Eigen安装的问题
1.无法打开包括文件: “Eigen/Core”: 去github上下载最新的源码 2. "The Eigen/Array header does no longer exist in E ...
- ES6 入门系列 (三) 尾递归
递归我们不陌生, 那什么是尾递归呢? 为什么要用尾递归呢? 尾递归怎么用呢? 带着这三个问题我们来了解它, 我们知道递归非常耗费内存,一不小心就会发生‘栈溢出’, 相信你一定遇到过这个错误: stac ...
- JavaWeb 发送邮件
我们可以使用第三方的邮箱服务器来发送邮件. 常用的邮件传输协议有2种:POP3/SMTP.IMAP/SMTP. POP和IMAP的区别:在邮箱客户端的操作,比如移动邮件.标记已读,如果使用POP,是不 ...
- linux下使用selenium
安装chromedriver 1.安装chrome 用下面的命令安装最新的 Google Chrome yum install https://dl.google.com/linux/direct/g ...
- Hexo主题开发
序章 想要一个自己的知识管理系统,用了 Hexo ,但是没有发现自己心仪的主题,就自己做了一个.本文记录了制作的全过程.本人编码功底和前端知识并不是特别雄厚,希望能由此文引出各路大神的兴趣,以后制作出 ...
- sqlserver清空删除日志
USE [lzdxdb] GO ALTER DATABASE lzdxdb SET RECOVERY SIMPLE WITH NO_WAIT GO ALTER DATABASE lzdxdb SET ...
- AI-图像基础知识-02
目录 图像坐标系 图像数字化 图像坐标系 在前面的数据标注文章中讲述如何进行标注,而标注后会保留4个坐标点,那么这些坐标点如何表示在图片中的位置?要表示一个点或图形的位置,就需要涉及到坐标系的 ...