Spring提供了一个AOP框架,让我把切面插入到方法执行的周围。
1、概念
定义通用功能,通过申明定义这些功能要以何种方式在何处应用,而不需要修改受影响的类。这些通用功能可以模块化为特殊的类,即切面。
- 连接点:连接点是一个应用执行过程中能够插入一个切面的点(Spring只支持方法级别的连接点)
- 切点:定义匹配通知织入的一个或多个连接点(在哪做)
- 通知:切面的工作(做什么)
- 切面:由切点和通知的结合
- 织入:把切面应用到目标对象并创建新的代理对象的过程
通知分类
- 前置通知:在目标方法调用之前执行
- 后置通知:在目标方法执行之后执行,不管是正常执行还是抛了异常
- 返回通知:在目标方法执行成功后执行,不管方法是否有返回值
- 异常通知:在目标方法抛出异常后调用
- 环绕通知:通知方法将目标方法封装起来,可以达到前几种通知的效果
2、Spring切面编程分为:基于注解和基于XML配置形式
- 基于注解形式
首先开启Aspect代理功能
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
定义切面,并将该bean交给spring管理
package com.cn.pojo; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Component @Aspect public class Audience { @Pointcut("execution(* com.cn.pojo.Performance.*(..))") public void performance(){} @Before("performance()") public void takeSeats(){ System.out.println( "Before:take seats!"); } @After("performance()") public void goHome(){ System.out.println("After:go home!"); } @AfterReturning(value = "performance()", returning = "result") public void applause(JoinPoint joinPoint,Object result){ System.out.println("AfterReturning:clap clap clap!"); System.out.println("AfterReturning:"+joinPoint.getArgs()[0]); System.out.println("AfterReturning:applause-当前在场人数:"+result); } @AfterThrowing(value = "performance()", throwing = "ex") public void demandRefund(JoinPoint joinPoint, Exception ex){ System.out.println("AfterThrowing:demanding a refund!"); System.out.println("AfterThrowing:"+joinPoint.getArgs()[0]); System.out.println("AfterThrowing:异常信息为 "+ex.getMessage()); } @Around("performance()") public Object all(ProceedingJoinPoint proceedingJoinPoint){ try{ System.out.println("Around:执行perform方法-前置通知"); Object obj=proceedingJoinPoint.proceed(new Object[]{189}); System.out.println("Around:执行perform方法-返回通知"); return obj; }catch (Throwable throwable) { System.out.println("Around:执行perform方法-异常通知"); return -1; }finally { System.out.println("Around:执行perform方法---后置通知"); } } }
除了execution外,还有以下指示器用于定义切点:
方法入参切点函数
|
args()
|
类名
|
通过判别目标类方法运行时入参对象的类型定义指定连接点。如args(com.baobaotao.Waiter)表示所有有且仅有一个按类型匹配于Waiter的入参的方法。
|
@args()
|
类型注
解类名
|
通过判别目标方法的运行时入参对象的类是否标注特定注解来指定连接点。如@args(com.baobaotao.Monitorable)表示任何这样的一个目标方法:它有一个入参且入参对象的类标注@Monitorable注解。
|
|
目标类切点函数
|
within()
|
类名匹配串
|
表示特定域下的所有连接点。如within(com.baobaotao.service.*)表示com.baobaotao.service包中的所有连接点,也即包中所有类的所有方法,而within(com.baobaotao.service.*Service)表示在com.baobaotao.service包中,所有以Service结尾的类的所有连接点。
|
target()
|
类名
|
假如目标类按类型匹配于指定类,则目标类的所有连接点匹配这个切点。如通过target(com.baobaotao.Waiter)定义的切点,Waiter、以及Waiter实现类NaiveWaiter中所有连接点都匹配该切点。
|
|
@within()
|
类型注解类名
|
假如目标类按类型匹配于某个类A,且类A标注了特定注解,则目标类的所有连接点匹配这个切点。
如@within(com.baobaotao.Monitorable)定义的切点,假如Waiter类标注了@Monitorable注解,则Waiter以及Waiter实现类NaiveWaiter类的所有连接点都匹配。
|
|
@target()
|
类型注解类名
|
目标类标注了特定注解,则目标类所有连接点匹配该切点。如@target(com.baobaotao.Monitorable),假如NaiveWaiter标注了@Monitorable,则NaiveWaiter所有连接点匹配切点。
|
- 基于XML方式
定义POJO
package com.cn.pojo; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; public class Audience { public void takeSeats(){ System.out.println( "Before:take seats!"); } public void goHome(){ System.out.println("After:go home!"); } public void applause(JoinPoint joinPoint,Object result){ System.out.println("AfterReturning:clap clap clap!"); } public void demandRefund(JoinPoint joinPoint, Exception ex){ System.out.println("AfterThrowing:demanding a refund!"); } public Object all(ProceedingJoinPoint proceedingJoinPoint){ try{ System.out.println("Around:执行perform方法-前置通知"); Object obj=proceedingJoinPoint.proceed(new Object[]{189}); System.out.println("Around:执行perform方法-返回通知"); return obj; }catch (Throwable throwable) { System.out.println("Around:执行perform方法-异常通知"); return -1; }finally { System.out.println("Around:执行perform方法---后置通知"); } } }
将POJO申明为切面,并交spring管理
<aop:config> <aop:aspect ref="audience"> <aop:pointcut id="perform" expression="execution(* com.cn.pojo.Performance.*(..))"></aop:pointcut> <aop:before method="takeSeats" pointcut-ref="perform"></aop:before> <aop:after method="goHome" pointcut-ref="perform"></aop:after> <aop:after-returning method="applause" pointcut-ref="perform" returning="result"></aop:after-returning> <aop:after-throwing method="demandRefund" pointcut-ref="perform" throwing="ex"></aop:after-throwing> <aop:around method="all" pointcut-ref="perform"></aop:around> </aop:aspect> </aop:config>