-
-
切面=切入点+增强
-
切面=切入点+方位信息+横切逻辑
-
切面=连接点+横切逻辑
-
-
在Spring中,增强除了用于描述横切逻辑外,包含一层意思就是横切逻辑执行的方位信息。刚刚说了切点只能定位到方法,在进一步使用方位信息就可以定位到我们感兴趣的连接点了(方法调用前、方法调用后还是方法抛出异常时等)。
<!--aop的jar包支持--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.1.12.RELEASE</version> </dependency> <!--aop 依赖支持--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.9</version> </dependency>
execution(
[modifiers-pattern] //修饰符匹配 可省略
ret-type-pattern //返回值匹配
[declaring-type-pattern](paraname) //类路径+方法名匹配+参数
[throws-pattern] //异常类型匹配
)
- [modifiers-pattern]:修饰符匹配,例如public等修饰符列表中的修饰符。
- ret-type-pattern:返回值匹配可为 * 或 void 或 具体返回值的全限定类名。必填
- [declaring-type-pattern](paraname):格式 包名.类名.方法名(参数)
- 没有参数则为空不填 methName()。
- 有具体参数需要写具体参数的全限定类名
- 一个参数可以使用 methName(*)
- 若干参数使用 methName(..)
- 若参数是lang包下数据类型,则省略全限定包名直接写数据类型
- [throws-pattern]:方法异常信息
现在来看看几个例子
1)com.spring.service.UserServiceImpl包下的saveAll()方法,无返回值,修饰符public
execution(public void com.spring.service.UserServiceImpl.saveAll())
2)省略修饰符,com.spring.service.UserServiceImpl包下的deleteUser方法,参数为Integer 无返回值
execution(void com.spring.service.UserServiceImpl.deleteUser(Integer))
3)省略修饰符,com.spring.service.UserServiceImpl包下的updateUser方法,参数为User 返回值User
execution(com.spring.domain.User com.spring.service.UserServiceImpl.updateUser(com.spring.domain.User)
4)所有参数类型,所有包(有几层包写几个*.)类下的方法
execution(* *.*.*.UserServiceImpl.updateUser(com.spring.domain.User))
5)所有参数类型, ..表示当前包及其子包下所有 类的 所有方法,且此方法只有一个所有满足参数类型的方法
execution(* com..*.*(*))
6)所有参数累心,所有包下所有方法,且满足有参和无参,满足多个参数
execution(* *..*.*(..))
execution(* *(..)) 效果相同
注:第六种写法会把符合情况的所有包匹配到,所以通常情况下我们都是对业务层的方法进行增强,所以切入点表达式都是切到业务层实现类。
execution(* com.itheima.service.impl.*.*(..))
作用:用于配置前置通知。指定增强的方法在切入点方法之前执行。
执行时间点:切入点方法执行之前执行。
作用:用于配置后置通知。指定增强的方法在切入点方法之后执行。
执行时间点:切入点方法正常执行之后。抛出异常就不执行了。
XML配置需要的标签
<!-- 作用 : 用于配置AOP --> <aop:config> <!--标签作用: 声明一个切面 id属性 : 当前切面的唯一标识 ref : 当前切面功能增强的对象 --> <aop:aspect id="" ref="logUtils"> <!--配置前置通知【在方法之前加功能】 <aop:before>前置通知标签 method属性 : 指的是要增强的功能方法 pointcut属性 : 切入点表达式 pointcut-ref属性 : 导入外部的切入点表达式 --> <aop:before method="" pointcut=""/> <!--配置后置通知【在方法之后加功能】--> <aop:after-returning method="afterReturningPrintLog"pointcut="execution(* com.spring.service.UserServiceImpl.*(..))"/>
<!--配置异常通知【在方法出现时候加功能】-->
<aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pointcutService"/>
<!--配置最终通知【在方法执行完毕,最终加功能】-->
<aop:after method="" pointcut=""/>
<!--配置环绕通知: 四合一通知 抽取相同表达式 id属性注入到上面的pointcut-ref属性-->
<aop:pointcut id="pointcutService" expression="execution(* com.spring.service.UserServiceImpl.*(..))"/>
代码实现和xml配置
有一个日志类
public class LogAopUtils { //在目标方法执行前 public void beforePrintLog() { System.out.println("方法执行之前,输出日志"); } //在目标方法执行之后,输出日志的方法 public void afterReturningPrintLog() { System.out.println("方法执行之后,输出日志"); } //在目标方法出现异常,输出日志的方法 public void afterThrowingPrintLog() { System.out.println("方法执行过程出现了异常,输出日志"); } //在目标方法最终时刻,输出日志的方法 public void afterPrintLog() { System.out.println("方法执行最终,输出日志"); }
/** * 环绕通知对应的功能 增强: 对应四合一 * 要求必须要传递一个参数: ProceedingJoinPoint */ public void aroundPrint(ProceedingJoinPoint joinPoint) { try { //前置通知 System.out.println("方法执行之前"); joinPoint.proceed(joinPoint.getArgs());//作用,执行被拦截的方法。类似于method.invoke() //后置通知 System.out.println("方法执行之后"); } catch (Throwable throwable) { throwable.printStackTrace(); //异常通知 System.out.println("方法出异常了"); } finally { //最终通知 System.out.println("方法执行最终节点"); } } }
https://www.cnblogs.com/xiaozhang666/p/12132408.html ProceedingJoinPoint 详解
xml配置
<context:component-scan base-package="com"></context:component-scan> <bean id="logAopUtils" class="com.spring.utils.LogAopUtils"></bean> <aop:config> <aop:aspect id="logAspect" ref="logAopUtils"> <aop:before method="beforePrintLog" pointcut-ref="pointcutService"/> <aop:after-returning method="afterReturningPrintLog" pointcut-ref="pointcutService"/> <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pointcutService"/> <aop:after method="afterPrintLog" pointcut-ref="pointService"/> <aop:pointcut id="pointcutService" expression="execution(* com.spring.service.UserServiceIml.*(..))"/> <!--配置环绕通知: 四合一通知--> <aop:around method="aroundPrint" pointcut-ref="pointcutService"/> </aop:aspect> </aop:config>