zl程序教程

您现在的位置是:首页 >  后端

当前栏目

spring学习笔记(13)基于Schema配置AOP详解

Spring配置笔记学习AOP 详解 基于 13
2023-09-14 08:57:15 时间
 bean id="transactionManager" 

 property name="dataSource" ref="dataSource" / /bean 

 !-- 拦截器方式配置事物 -- 

 tx:advice id="transactionAdvice" transaction-manager="transactionManager" !--事务的增强配置-- 

 tx:attributes 

 tx:method name="add*" propagation="REQUIRED" / 

 !--name="add*"相当于我们的函数切点表达式,匹配以add开头的方法,使用REQUIRED的事务传播行为-- 

 tx:method name="save*" propagation="REQUIRED" / 

 tx:method name="modify*" propagation="REQUIRED" / 

 tx:method name="delete*" propagation="REQUIRED" / 

 tx:method name="get*" propagation="SUPPORTS" / 

 tx:method name="search*" propagation="SUPPORTS" / 

 tx:method name="*" propagation="SUPPORTS" / 

 /tx:attributes 

 /tx:advice 

 aop:config !--aop命名空间配置的开始-- 

 aop:pointcut id="transactionPointcut"

 !--这里也是切点,和前面的 tx:method name="add* 取交来定位连接点-- 

 aop:advisor pointcut-ref="transactionPointcut"

 advice-ref="transactionAdvice" / 

 !--通过整合切点和增强来配置我们的切面(advisor),从配置中我们看到,这种切面的增强和切点都是唯一的-- 

 /aop:config 

以上实例就是我们基于Schema的方式来配置切面,这样,我们com.yc.service包下,以Impl结尾的类中所有的方法都会根据方法名织入相应的事务,就不用之前繁琐地硬编码式为每个方法配置事务了。


import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.Ordered; public class MyAdvice { public void AfterReturning(Object retInfo) throws Throwable{ System.out.println("MyAdvice 实施AfterReturning,目标对象方法返回值为:"+retInfo); public void after(String name) throws Throwable{ System.out.println("MyAdvice 实施after,目标对象方法入参为:"+name); public void before(String name) throws Throwable{ System.out.println("MyAdvice 实施@before,目标对象方法入参为:"+name); public void around(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("MyAdvice 实施around前,目标对象方法入参为:"+joinPoint.getArgs()[0]); joinPoint.proceed(); System.out.println("MyAdvice 实施around后,目标对象方法入参为:"+joinPoint.getArgs()[0]); public void afterThrowing(RuntimeException re) throws Throwable{ System.out.println("MyAdvice 实施afterThrowing,目标对象方法抛出异常:"+ re.getMessage()); }
!-- 基于Schema配置必须以 aop:config 开始 ,可配置是否暴露AOP代理,或是否使用CGLib代理-- aop:pointcut expression="target(test.aop3.UserController) and args(name) " id="pointcut"/ !-- 配置独立切点,方便在后面的切面配置中服用 -- !-- 配置切面,通过ref引入增强类,通过order配置织入顺序 -- aop:before method="before" pointcut-ref="pointcut" arg-names="name"/ !-- 通过arg-names绑定目标对象的方法入参 名字需和增强的方法入参一致-- !-- 除了通过pointcut-ref属性引用独立命名切点,还可以通过pointcut属性声明并引用匿名切点 -- aop:around method="around" pointcut="execution( * test.aop3.UserController.login(..))"/ aop:after method="after" pointcut-ref="pointcut" arg-names="name"/ !--绑定目标对象方法的返回值到增强方法入参,名字需一致 -- aop:after-throwing method="afterThrowing" pointcut="target(test.aop3.UserController)" throwing="re"/ /aop:aspect /aop:config
public static void main(String args[]){

 ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:test/aop3/aop.xml");

 UserController userController = (UserController) ac.getBean("userController");

 userController.login("zenghao");

 userController.logout();

}

MyAdvice 实施@before,目标对象方法入参为:zenghao
MyAdvice 实施around前,目标对象方法入参为:zenghao
I’m zenghao ,I’m logining
MyAdvice 实施around后,目标对象方法入参为:zenghao
MyAdvice 实施after,目标对象方法入参为:zenghao
MyAdvice 实施AfterReturning,目标对象方法返回值为:null
MyAdvice 实施afterThrowing,目标对象方法抛出异常:illegal logout
Exception in thread “main” java.lang.RuntimeException: illegal logout
at test.aop3.UserController.logout(UserController.java:10)
at test.aop3.UserController$$FastClassBySpringCGLIB$$d89843a8.invoke()
……(忽略下面异常信息)……


结合上面实例,我们分析:
1. aop切点、切面等配置必须被 aop:config 标签包括
2. 一个 aop:config 可以配置多个切点、切面,一个切面可以配置多个增强
3. aop:pointcut 可以配置在 aop:config 和 aop:aspect 中,配置在 aop:config 中对所 有 aop:aspect 可见,配置在特定的 aop:aspect 则对其他的 aop:aspect 不可见。
4. 在 aop:config 中,各标签配置顺序先后依序必须为: aop:pointcut 、 aop:advisor 、 aop:aspect ,若 aop:pointcut 配置在 aop:aspect 中,则无顺序要求(即在 aop:after 等标签前后都可以,即使 aop:after 标签中引用了该 aop:pointcut 标签)
5. 在xml文件中使用逻辑运算符 会报错,必须使用and,||和!则无此限制


在前面的例子中,我们没有提到引介增强,实际上,引介增强的配置和其他增强的差异是挺大的,它没有了method,pointcut,pointcut-ref属性,但多了以下四个属性:
1. implement-interface
2. default-impl
3. implement-interface
4. delegate-ref
关于引介增强的各种配置和现实应用场景分析,请移步至我的另外一篇博文《spring学习笔记(12)引介增强详解:定时器实例:无侵入式动态增强类功能》查看。


前面我们在谈等几个标签的配置顺序中提到,它的使用格式为:
aop:advisor advice-ref="实现了特定的增强接口的增强类" order="1" pointcut="使用切点表达式函数定义切点"/
其中,实现了特定增强的接口实现类配置可参考我前面的文章:spring学习笔记(6)AOP增强(advice)配置与应用 ,它的配置形式如:


throws Throwable { System.out.println("前置日志记录:"+target+ "调用了"+method.getName() + "方法,传入的第一个参数为:"+args[0]); }
Spring 源码阅读 62:基于 JDK 的 AOP 代理对特殊方法调用的处理 本文深入分析了 JdkDynamicAopProxy 的invoke方法的第一部分逻辑,也就是,对于哪些方法的调用,不对其进行增强,而是执行对应的特定逻辑,从中可以了解,Spring AOP 对哪些方法是默认不进行增强的。
Spring 源码阅读 61:基于 JDK 动态代理的 AOP 代理回调方法 invoke 分析 本文分析了 JdkDynamicAopProxy 的invoke方法,invoke方法是基于 JDK 动态代理创建的 AOP 代理对象的方法处理回调逻辑,也是 Spring AOP 增强目标方法的关键逻辑。
阿里特邀专家徐雷Java Spring Boot开发实战系列课程(第18讲):制作Java Docker镜像与推送到DockerHub和阿里云Docker仓库 立即下载