实现简单的AOP前置后置增强
发布日期:2021-05-09 09:33:40 浏览次数:26 分类:博客文章

本文共 4032 字,大约阅读时间需要 13 分钟。

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
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
(); } //执行拦截器链 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()方法顺序,不一样的话,会有不同的结果哦.

上一篇:了解jsp,这一篇就够了.
下一篇:浅谈设计模式-visitor访问者模式

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2025年04月19日 20时45分21秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

hp工作站z8装Linux,惠普Z8G4双路最小工作站 2023-01-24
html上传图片直接保存到数据库中,Editor上传图片路径存入数据库中怎么弄? 2023-01-24
html游戏玩不了,WinXP网页游戏玩不了怎么办有哪些解决方法 2023-01-24
html转jsp_JSP详解 2023-01-24
ICLOUD储存空间要升级吗_有人像我一样需要恢复苹果手机icloud空间ios备份时 微信卡住不动了吗(已解决)... 2023-01-24
image unity 原始尺寸_Unity基础教程-对象管理(十一)——生命周期(Growth and Death)... 2023-01-24
iphone打字怎么换行_手持iPhone?你可能并不知道的小技巧! 2023-01-24
jaccard相似度_自然语言处理之文本相似度计算 2023-01-24
java 8 list对象属性判空_java ---- 认识类对象,属性和方法 2023-01-24
java http delete_java积累---HttpDelete请求方式传递参数 2023-01-24
java swing数据库,如何在Java swing中查看数据库结果集 2023-01-24
java xmpp 群聊,使用XMPPFramework openfire创建聊天室 2023-01-24
java 反义_java中一些常用的英语 2023-01-24
java 命令行 class_如何从命令行执行java .class 2023-01-24
java 字符编码过滤器_java web中字符编码的过滤器(Filter - 1) 2023-01-24
java 线程 栈_Java线程堆栈分析 2023-01-24
#pragma data_seg() 共享数据// MyData段 // 进程 // DLL 2023-01-24
#NOIP前数学知识总结 2023-01-24
java书籍_还搞不定Java多线程和并发编程面试题?你可能需要这一份书单! 2023-01-24
java序列化_java对象的序列化和反序列化 2023-01-24