Spring boot AOP通过XML配置文件声明的方法
作者:CurtainMy
通过 XML 配置文件声明
在前两篇博文和示例中,我们已经展示了如何通过注解配置去声明切面,下面我们看看如何在 XML 文件中声明切面。下面先列出 XML 中声明 AOP 的常用元素:
AOP配置元素 | 用途 |
---|---|
aop:advisor | 定义AOP通知器 |
aop:after | 定义AOP后置通知(不管被通知的方法是否执行成功) |
aop:after-returning | 定义AOP返回通知 |
aop:after-throwing | 定义AOP异常通知 |
aop:around | 定义AOP环绕通知 |
aop:aspect | 定义一个切面 |
aop:aspectj-autoproxy | 启用@AspectJ注解驱动的切面 |
aop:before | 定义一个AOP前置通知 |
aop:config | 顶层的AOP配置元素。大多数的aop:*元素必须包含在aop:config元素内 |
aop:declare-parents | 以透明的方式为被通知的对象引入额外的接口 |
aop:pointcut | 定义一个切点 |
XML 配置文件中切点指示器
在XML配置文件中,切点指示器表达式与通过注解配置的写法基本一致,区别前面有提到,即XML文件中需要使用 “and”、“or”、“not”来表示 “且”、“或”、“非”的关系。
XML 文件配置 AOP
新建OrderXmlAop.java:
package com.example.demo.aop; public class OrderXmlAop { /** * @description 在连接点执行之前执行的通知 */ public void doBefore(){ System.out.println("阿里阿塞哟!"); } /** * @description 在连接点执行之后执行的通知(返回通知和异常通知的异常) */ public void doAfter(){ System.out.println("after!"); } /** * @description 在连接点执行之后执行的通知(返回通知) */ public void doAfterReturning(){ System.out.println("返回通知:AfterReturning"); } /** * @description 在连接点执行之后执行的通知(异常通知) */ public void doAfterThrowing(){ System.out.println("异常通知:AfterThrowing"); } }
在 Resource 目录下新建一个配置文件 aoporder.xml :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="wmzService" class="com.example.demo.service.impl.WMZServiceImpl"></bean> <bean id="zsService" class="com.example.demo.service.impl.ZSServiceImpl"></bean> <!-- 切面类 --> <bean id="OrderXmlAop" class="com.example.demo.aop.OrderXmlAop"></bean> <!-- Aop配置 --> <aop:config proxy-target-class="true"> <!-- 切面 --> <aop:aspect ref="OrderXmlAop"> <!-- 前置通知: 在目标方法调用前执行 --> <aop:before pointcut="execution(public * com.example.demo.service.TakeawayService.*(..)))" method="doBefore"/> <!-- 后置通知: --> <aop:after pointcut="execution(public * com.example.demo.service.TakeawayService.*(..)))" method="doAfter"/> <!-- 返回后通知 --> <aop:after-returning pointcut="execution(public * com.example.demo.service.TakeawayService.*(..)))" method="doAfterReturning"/> <!-- 异常通知 --> <aop:after-throwing pointcut="execution(public * com.example.demo.service.TakeawayService.*(..)))" method="doAfterThrowing"/> </aop:aspect> </aop:config> </beans>
新建 TakeXmlController.java
package com.example.demo.controller; import com.example.demo.entity.Response; import com.example.demo.entity.ResponseResult; import jdk.internal.org.objectweb.asm.tree.analysis.Value; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.example.demo.service.TakeawayService; @RestController @RequestMapping("/api") public class TakeXmlController { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("aoporder.xml"); @RequestMapping("/orderxml") public ResponseResult Ordexml() { /** ** 注意 此处的getBean(name)中的name 必须要和aoporder.xml 配置的bean节点上的id 保持一致 * 如: <bean id="wmzService" class="com.example.demo.service.impl.WMZServiceImpl"></bean> * TakeawayService wmzService=(TakeawayService)context.getBean("wmzService"); */ TakeawayService wmzService=(TakeawayService)context.getBean("wmzService"); String wmz= wmzService.Order(12); System.out.println(wmz); TakeawayService zsService=(TakeawayService)context.getBean("zsService"); String zs=zsService.Order(4396); System.out.println(zs); return Response.makeOKRsp(wmz+";"+zs); } }
运行结果:
声明环绕通知
修改OrderXmlAop.java:
package com.example.demo.aop; import org.aspectj.lang.ProceedingJoinPoint; public class OrderXmlAop { /** * @description 在连接点执行之前执行的通知 */ public void doBefore(){ System.out.println("阿里阿塞哟!"); } /** * @description 在连接点执行之后执行的通知(返回通知和异常通知的异常) */ public void doAfter(){ System.out.println("after!"); } /** * @description 在连接点执行之后执行的通知(返回通知) */ public void doAfterReturning(){ System.out.println("返回通知:AfterReturning"); } /** * @description 在连接点执行之后执行的通知(异常通知) */ public void doAfterThrowing(){ System.out.println("异常通知:AfterThrowing"); } /** * @description 在连接点执行之后执行的通知(异常通知) */ public void doAround(ProceedingJoinPoint pj) { try { System.out.println("Around 调用方法前 "); pj.proceed(); System.out.println("Around 调用方法后"); } catch (Throwable throwable) { throwable.printStackTrace(); } } }
aoporder.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="wmzService" class="com.example.demo.service.impl.WMZServiceImpl"></bean> <bean id="zsService" class="com.example.demo.service.impl.ZSServiceImpl"></bean> <!-- 切面类 --> <bean id="OrderXmlAop" class="com.example.demo.aop.OrderXmlAop"></bean> <!-- Aop配置 --> <aop:config proxy-target-class="true"> <!-- 切面 --> <aop:aspect ref="OrderXmlAop"> <!-- 环绕通知 --> <aop:around pointcut="execution(public * com.example.demo.service.TakeawayService.*(..)))" method="doAround"/> <!-- 前置通知: 在目标方法调用前执行 --> <aop:before pointcut="execution(public * com.example.demo.service.TakeawayService.*(..)))" method="doBefore"/> <!-- 后置通知: --> <aop:after pointcut="execution(public * com.example.demo.service.TakeawayService.*(..)))" method="doAfter"/> <!-- 返回后通知 --> <aop:after-returning pointcut="execution(public * com.example.demo.service.TakeawayService.*(..)))" method="doAfterReturning"/> <!-- 异常通知 --> <aop:after-throwing pointcut="execution(public * com.example.demo.service.TakeawayService.*(..)))" method="doAfterThrowing"/> </aop:aspect> </aop:config> </beans>
运行结果:
结果和我们预期的一致,环绕通知通过xml配置成功。
XML 文件配置声明切点
在上面的例子中,我们发现有切点表达式多次重复出现,那么可不可以和aspectj配置一样,单独声明切点,后面复用,答案是当然可以。如下修改aoporder.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="wmzService" class="com.example.demo.service.impl.WMZServiceImpl"></bean> <bean id="zsService" class="com.example.demo.service.impl.ZSServiceImpl"></bean> <!-- 切面类 --> <bean id="OrderXmlAop" class="com.example.demo.aop.OrderXmlAop"></bean> <!-- Aop配置 --> <aop:config proxy-target-class="true"> <!-- 切点 --> <aop:pointcut id="point" expression="execution(public * com.example.demo.service.TakeawayService.*(..)))"/> <!-- 切面 --> <aop:aspect ref="OrderXmlAop"> <!-- 环绕通知 --> <aop:around pointcut-ref="point" method="doAround"/> <!-- 前置通知: 在目标方法调用前执行 --> <aop:before pointcut-ref="point" method="doBefore"/> <!-- 后置通知: --> <aop:after pointcut-ref="point" method="doAfter"/> <!-- 返回后通知 --> <aop:after-returning pointcut-ref="point" method="doAfterReturning"/> <!-- 异常通知 --> <aop:after-throwing pointcut-ref="point" method="doAfterThrowing"/> </aop:aspect> </aop:config> </beans>
修改后执行结果:
XML文件配置为通知传递参数
修改OrderXmlAop.java
public String doAround(ProceedingJoinPoint pj,double price) { try { System.out.println("Around 调用方法前 "); pj.proceed(); if(price>=4396) { System.out.println("zs下单超过了4399,赠送一份鲜果饮汇源牌饮料"); return "爆浆牛丸和饮料"; } System.out.println("Around 调用方法后"); } catch (Throwable throwable) { throwable.printStackTrace(); } return "爆浆牛丸"; }
修改aoporder.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="wmzService" class="com.example.demo.service.impl.WMZServiceImpl"></bean> <bean id="zsService" class="com.example.demo.service.impl.ZSServiceImpl"></bean> <!-- 切面类 --> <bean id="OrderXmlAop" class="com.example.demo.aop.OrderXmlAop"></bean> <!-- Aop配置 --> <aop:config proxy-target-class="true"> <!-- 切点 --> <aop:pointcut id="point" expression="execution(com.example.demo.service.TakeawayService.Order(double)) and args(price) and bean(zsService)"/> <!-- 切面 --> <aop:aspect ref="OrderXmlAop"> <!-- 环绕通知 --> <aop:around pointcut-ref="point" method="doAround"/> </aop:aspect> </aop:config> </beans>
总结
本文主要通过XML配置文件使用 Spring AOP进行编程,和上一篇的注解方式两者联系起来对于刚入门的应该多多少少还是有点帮助的吧,针对于aop 通过三篇博客简单的描述,相信大家对此都有点印象了,记录了 AOP 的编程思想,然后介绍了 Spring 中 AOP 的相关概念,以及通过注解方式和XML配置文件两种方式使用 Spring AOP进行编程。所以对aop的博文就简单到这儿了,有人要问了,aop里面的代理啊还有各种各样的,如果真要吧aop重头到尾来一遍的话,这个系列可以单独提出来一个专栏了,所以后面的博文应该都是围绕连接数据库,记录日志,接入swagger文档等功能相继展开了。在此过程中,我有错误使用的地方,或者表达有问题,还请您及时告知,本人会在第一时间予以改正。最后在祝大家周末愉快,C Y L L