Sring AOP通过PointCut来指定在那些类的那些方法上织入横切逻辑,通过Advice来指定在切点上具体做什么事情。如方法前做什么,方法后做什么,抛出异常做什么。

再来看一下图

定义PointCut

Spring中有两种方式定义Pointcut:

  • XML文件
  • 注解

在xml文件中,入门中做了的演示:


<aop:config><!-- 定义切点 --><aop:pointcut id="hello" expression="execution(public * * (..))"></aop:pointcut>...
</aop:config>

注解的方式:

@Component
@Aspect
public class HelloWorld {@Pointcut("execution(public * * (..))")public void sayHello(){System.out.println("hello");}...
}

XML与注解方式类似,学会了一种,另外一种无难度上手,我们使用XML演示。

增强(Advice)

通过Idea,看一下Advice接口的接口继承类:
[图片上传失败...(image-d49d25-1530458748566)]

主要可分为5类增强:

  • MthodBeforeAdvice:目标方法实施前增强

  • AfterReturningAdvice:目标方法实施后增强

  • ThrowsAdvice 异常抛出增强

  • IntroductionAdvice 引介增强,为目标类添加新的属性和方法。可以构建组合对象来实现多继承

  • MethodInterceptor 方法拦截器,环绕增强,在方法的前后实施操作

AfterAdvice,BeforeAdvice当前是作为标记使用,内部无接口方法,为后来扩展使用。
Interceptor接口也不是直接使用,同样作为标记类,可使用其子接口。

前置增强

前置增强主要在匹配到的切点运行之前执行,在XML配置中使用<aop:before>,相应的接口为MethodBeforeAdvice,其方法为

    /*** @param method 要被激发的方法* @param args 方法的参数* @param target 目标对象,可能为null* @throws Throwable 如果这个对象想要终止调用,那么抛出异常,异常会返回给方法调用者,否则异常会被包装为运行时异常*/
void before(Method method, Object[] args, Object target) throws Throwable;

当一个Bean对象实现了MethodBeforeAdvice,在XML配置文件中指定这个bean为advice,Spring会自动在切点方法执行前执行MethodBeforeAdvice的接口。

    <bean id="helloworld" class="me.aihe.exam.controller.HelloWorld" /><!-- timelog实现了MethodBeforeAdvice接口 --><bean id="timeLog" class="me.aihe.exam.controller.TimeLoggingAop" /><aop:config><aop:pointcut id="hello" expression="execution(public * * (..))"></aop:pointcut><!-- advisor的作用为将Pointcut和Advice组装起来 --><aop:advisorid="timelogAdvisor"advice-ref="timeLog"pointcut-ref="hello"/></aop:config>

在调用相应的切点方法之前,前置增强都会生效。

后置增强

弄明白了前置增强,后置增强也是同一个道理,不过后置增强是在切点运行后执行。接口为AfterReturningAdvice,方法为

/*** 当方法成功返回之后运行* @param returnValue 如果方法有返回值,那么returnValue就是返回值* @param method 激发的方法* @param args 方法的参数* @param target 目标对象* @throws Throwable 同上*/void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;

在切点方法运行之后,后置增强会生效。

异常抛出增强

当切点方法抛出异常时,异常抛出增强才会被执行。其接口为ThrowsAdvice,接口没有指定方法,实现这个接口的对象是通过反射来调用其增强方法的。

// 异常增强方法格式如下
// 前面的三个参数是可选的,ThrowableSubclass为Throwable的子类
void afterThrowing([Method, args, target], ThrowableSubclass)//案例如下
public void afterThrowing(Exception ex)
public void afterThrowing(RemoteException)
public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)

增强案例

根据前面的前置,后置,异常抛出增强,看一个完整的案例:

// TimeLoggingAop实现了前置增强,后置增强,异常环绕增强
public class TimeLoggingAop implements MethodBeforeAdvice,AfterReturningAdvice,ThrowsAdvice {private long startTime = 0;@Overridepublic void before(Method method, Object[] objects, Object o) throws Throwable {startTime = System.nanoTime();}@Overridepublic void afterReturning(Object returnValue, Method method, Object[] objects, Object target) throws Throwable {long spentTime = System.nanoTime() - startTime;String clazzName = target.getClass().getCanonicalName();String methodName = method.getName();System.out.println("执行" + clazzName + "#" + methodName + "消耗" + new BigDecimal(spentTime).divide(new BigDecimal(1000000)) + "毫秒");}public void afterThrowing(Method method, Object[] args, Object target, Exception ex){System.out.println("执行" + method.getName() + "出现异常," + "异常消息为:" + ex.getMessage());}
}
// 普通的HelloWorld对象
public class HelloWorld {public void sayHello(){System.out.println("hello");}public void sayHelloWithException(){System.out.println("hello");throw new RuntimeException("Hello World运行时出了一点问题");}
}public static void main(String[] args) {//普通对象HelloWorld helloWorld = new HelloWorld();//增强对象BeforeAdvice beforeAdvice = new TimeLoggingAop();//组装普通对象和增强对象ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(helloWorld);proxyFactory.addAdvice(beforeAdvice);//获取组装后的代理对象HelloWorld proxyHelloWorld = (HelloWorld) proxyFactory.getProxy();//运行proxyHelloWorld.sayHello();proxyHelloWorld.sayHelloWithException();}//运行结果
hello
执行me.aihe.exam.controller.HelloWorld#sayHello消耗29.392268毫秒hello
执行sayHelloWithException出现异常,异常消息为:Hello World运行时出了一点问题

通过上面这个案例,我们大体知道什么是增强,字面意思:
在原本方法之上增加一些额外的东西,原本的功能增强了,所以叫增强,这是中文翻译过来的增强。
英文名为Advice,建议,在方法周围建议方法做什么事情,然后真的做了...

环绕增强

环绕增强可以理解为前置增强,后置增强,异常抛出增强的结合体,只有一个接口MethodInterceptor,其方法为:

// MethodInvocation封装了目标对象和参数数组,调用它的invocation.proceed()方法即激发目标对象的方法。
Object invoke(MethodInvocation invocation) throws Throwable;

一个用法案例:

    public Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("前置增强执行");try {Object result = invocation.proceed();System.out.println("后置增强执行");return result;}catch (Exception e){System.out.println("异常抛出增强执行");//做其它的动作}return null;}

增强顺序

当多个增强作用与同一个切点的时候,具体哪一个增强会先执行呢?

Spring根据@Order注解或者实现了Ordered接口的增强类来进行判断。

public interface Ordered {int HIGHEST_PRECEDENCE = -2147483648;int LOWEST_PRECEDENCE = 2147483647;int getOrder();
}

注解相关增强

增强的概念一样,在使用方式上稍微有点区别,增强的相关注解有:
@Before
@AfterReturning
@AfterThrowing(
@After //相当于try-catch-finally中的final,一般用于释放资源
@Around

使用上与接口差不多

最后

增强是AOP中核心概念之一,本文在增强上稍作一些探索,深入还要靠大家,最后希望能帮到大家

参考

  • 《Spring Reference》
  • 《精通Spring 4.x 企业级应用开发实战》

Spring AOP增强(Advice)相关推荐

  1. Spring AOP 增强框架 Nepxion Matrix 详解

    点击上方"方志朋",选择"置顶或者星标" 你的关注意义重大! 概述 在<深入聊一聊 Spring AOP 实现机制>一文中,介绍了 Spring A ...

  2. Spring AOP tx:advice

    Xml代码   <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http: ...

  3. Spring AOP 中 advice 的四种类型 before after throwing advice around

    Spring  AOP(Aspect-oriented programming) 是用于切面编程,简单的来说:AOP相当于一个拦截器,去拦截一些处理,例如:当一个方法执行的时候,Spring 能够拦截 ...

  4. Spring AOP 的 Advice 和 Advisor 有什么区别

    简单来说:Advice 是通知,Advisor 是增强器.(说了跟没说一样-) 使用 spring aop 要定义切面,切面里面有 通知 和 切点. 在项目启动的过程中,项目中的所有切面会被 Anno ...

  5. Spring Aop——给Advice传递参数

    给Advice传递参数 Advice除了可以接收JoinPoint(非Around Advice)或ProceedingJoinPoint(Around Advice)参数外,还可以直接接收与切入点方 ...

  6. 【小家Spring】Spring AOP各个组件概述与总结【Pointcut、Advice、Advisor、Advised、TargetSource、AdvisorChainFactory...】

    每篇一句 基础技术总是枯燥但有价值的.数学.算法.网络.存储等基础技术吃得越透,越容易服务上层的各种衍生技术或产品 相关阅读 [小家Spring]Spring AOP原理使用的基础类打点(AopInf ...

  7. Spring Aop 组件概述

    Spring Aop 概述 AOP(Aspect-Oriented Programming) 面向切面编程, 这种编程模型是在 OOP(Object-Oriented Programming) 的基础 ...

  8. Spring AOP(二)AOPAlliance与SpringAOP核心接口介绍

    目录 AOP联盟 1. Advice.MethodInterceptor拦截器(invoke方法:调用invocation.proceed) 2.Joinpoint .MethodInvocation ...

  9. 跟着小马哥学系列之 Spring AOP(Pointcut 组件详解)

    学好路更宽,钱多少加班. --小马哥 版本修订 2021.5.19:去除目录 2021.5.21:引用 Spring 官方 Pointcut 概念,修改 Pointcut 功能表述 简介 大家好,我是 ...

最新文章

  1. 【jquery】jquery选择器
  2. POJ 1426 Find The Multiple
  3. js笔记——call,apply,bind使用笔记
  4. 全球及中国区块链安全行业全景调研与十四五规划动向展望报告2021年版
  5. 【Qt】modbus之串口模式读操作
  6. 应用程序无法正常启动(0xc000007b)错误的解决
  7. 中澳科学家在量子安全通信领域合作研究取得突破性进展
  8. vim编辑器-缩进修改
  9. 刻录linux-iso至u盘工具,ISO USB刻录工具ISO to USB burning tool V1.5 完美版
  10. tensorflow dataset 用法 from_tensor_slices dataset.repeat dataset.batch dataset.shuffle
  11. 靶机渗透练习21-Noob
  12. [unity] unity学习——弹球游戏
  13. 【元胞自动机】基于元胞自动机模拟交通事故道路通行量matlab源码
  14. APIO2007风铃
  15. 使用安卓原生系统刷机,修改
  16. Maya10个非常实用的操作技巧,让你轻松玩转Maya
  17. 礼物帮手-论文(不全)
  18. 海量数据等概率选取问题
  19. 深度剖析CMOS、FinFET、SOI和GaN工艺技术
  20. DVWA 反射型XSS XSS(Reflected)题解

热门文章

  1. 分布式文件系统FastDFS+nginx的使用配置
  2. Eclipse和MyEclipse 手动设置 Java代码 注释模板
  3. (转)Objective-C中的instancetype和id区别
  4. awk中的NR和FNR
  5. python部署到hadoop上_python实现mapreduce(2)——在hadoop中执行
  6. iOS - Flutter混合开发
  7. Kali Linux软件更新日报20190622
  8. XamarinAndroid组件教程设置自定义子元素动画(二)
  9. python管道界面_python中管道用法入门实例
  10. 希尔排序是一种稳定的排序算法_全面解析十大排序算法之四:希尔排序