Spring AOP 基于AspectJ (2)

注意:参数类型必须为ProceedingJoinPoint,否则 无法执行原始方法,

异常通知 @AfterThrowing(value = "execution(* com.yh.demo1.PersonDao.save(..))",throwing = "e") public void exceptionHandler(JoinPoint point,Exception e){ System.out.println(point + " 方法出现"+e.getMessage()+"异常"); }

当方法中出现时才会执行该通知,若需要获取异常信息,可在注解中添加throwing指定参数名称

我们可以使用环绕+异常通知来处理数据库事务,在环绕中开启事务以及提交事务,异常通知中回滚事务,当然Spring已经对事务进行了封装不需要自己写

最终通知 @After(value = "execution(* *delete(..))") public void afterRun(){ System.out.println("最终"); }

最终通知叫做after 即调用原始方法之后执行无论原始方法中是否出现异常

而后置叫做afterReturning表示在成功返回后才会执行执行

带有逻辑符的表达式:

在表达式中可以使用户逻辑操运算符,与&& 或|| 非!

示例:

/* execution(* cn.xxx.service.UserDao.insert(..))||execution(* cn.xxx.service.UserDao.delete(..)) execution(* cn.xxx.service.UserDao.*nsert(..))&&execution(* cn.xxx.service.UserDao.inser*(..)) !execution(* cn.xxx.service.UserDao.insert(..)) */ 切点命名

假设有多个通知应用在同一个切点上时,我们需要重复编写execution表达式,且后续要修改切点时则多个通知都需要修改,维护起来非常麻烦,我们可以通过给切点指定名称从而完成对切点的重复使用和统一操作,以提高开发维护效率;

//定义命名切点 方法名称即切点名称 @Pointcut(value = "execution(* com.yh.demo1.PersonDao.save(..))") private void savePointcut(){} @Pointcut(value = "execution(* com.yh.demo1.PersonDao.delete(..))") private void deletePointcut(){}

多个通知应用到同一个切点:

//使用命名切点 @Before(value = "savePointcut()") public void beforeAdvice(){ System.out.println("before code run....."); } //使用命名切点 @Around(value = "savePointcut()") public void beforeAdvice2(ProceedingJoinPoint point) throws Throwable { System.out.println("环绕前"); point.proceed(); System.out.println("环绕后");

一个通知应用到多个切点

//同一个通知对应多个切点 @After(value = "savePointcut()||deletePointcut()") public void afterAdvice(){ System.out.println("after code run....."); } XML配置

XML配置所需的jar 以及各个对象之间的依赖关以及表达式的写法都是一样的,仅仅是换种方式来写而已;

xml:

<!--目标--> <bean/> <!--通知--> <bean/> <!--织入信息--> <aop:config> <!--切点定义--> <aop:pointcut expression="execution(* com.yh.demo2.StudentDao.select(..))"/> <!--切面定义--> <aop:aspect ref="advices"> <aop:before method="before" pointcut-ref="select"/> <aop:after-returning method="afterReturning" pointcut-ref="select" returning="result"/> <aop:after method="after" pointcut-ref="select" /> <aop:after-throwing method="exception" pointcut-ref="select" throwing="e"/> <aop:around method="around" pointcut-ref="select"/> </aop:aspect> <!--入侵式通知 即通知需要实现指定接口 两种不能同时使用 --> <aop:advisor advice-ref="advice2" pointcut-ref="select"/> </aop:config> <!--入侵式通知Bean--> <bean/>

通知类:

import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.JoinPoint; public class XMLAdvice { public void before(JoinPoint pointcut){ System.out.println("前置通知 切点:"+pointcut); } public void afterReturning(JoinPoint point,Object result){ System.out.println("后置通知 切点:"+point); } public void after(JoinPoint point){ System.out.println("最终通知 切点:"+point); } public void exception(JoinPoint point,Throwable e){ System.out.println("异常通知: " + e+"切点:"+point); } public void around(ProceedingJoinPoint point) throws Throwable { System.out.println("环绕前"); point.proceed(); System.out.println("环绕后"); } }

你会发现 ,无论是XML还是注解都不需要手动指定代理,以及目标对象,Aspectj会从切点中获取目标对象信息并自动创建代理;

AspectJ是目前更流行的方式,具体采用XML还是注解需要根据项目具体情况,小组协作开发推荐xml;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpsxxw.html