AOP 使用指南

举报
西魏陶渊明 发表于 2022/09/25 02:45:35 2022/09/25
【摘要】 作者: 西魏陶渊明 博客: https://springlearn.cn 真正的猛士,每天干一碗毒鸡汤! 问世间钱为何物,只叫人生死相许。!😄 # (opens new window) # 一、常用注...

作者: 西魏陶渊明

博客: https://springlearn.cn

真正的猛士,每天干一碗毒鸡汤!

问世间钱为何物,只叫人生死相许。!😄

#
(opens new window)

# 一、常用注解

注解 说明
@Before 前置通知, 在方法执行之前执行
@After 后置通知, 在方法执行之后执行
@AfterRunning 返回通知 在方法返回结果之后执行
@AfterThrowing 异常通知在方法抛出异常之后
@Around 环绕通知, 围绕着方法执行

# 二、切面表达式

注解 说明
within 拦截指定类及指定包下所有的类
@within 拦截被指定注解修饰的类
this 拦截指定的类型
args 拦截指定参数类型的方法
@annotation 拦截带指定注解的方法
@args 拦截方法入参被中@args指定的注解(入参只能有一个)
execution 表达式详情见下文

# 三、API使用案例

# 3.1 within

# a. API说明

  1. 精确匹配类名
  2. 模糊匹配包中所有的类
  3. 模糊匹配包中所有的带Impl后缀的

# b. 目录


    
  1. └── WithinMatchProcessor
  2. ├── AopWithinMatchProcessor.java
  3. ├── CokeImpl.java
  4. ├── Water.java
  5. └── readme.md
1 2 3 4 5

# c. 拦截代码


    
  1. @Aspect
  2. @Component
  3. public class AopWithinMatchProcessor {
  4. /**
  5. * 精确匹配类名
  6. */
  7. @Pointcut("within(spring.learning.aop.WithinMatchProcessor.Water)")
  8. private void matchClassName() {
  9. }
  10. /**
  11. * 模糊匹配包中所有的类
  12. */
  13. @Pointcut("within(spring.learning.aop.WithinMatchProcessor.*)")
  14. private void matchAllClassFromPackage() {
  15. }
  16. /**
  17. * 模糊匹配包中所有的带Impl后缀的
  18. */
  19. @Pointcut("within(spring.learning.aop.WithinMatchProcessor.*Impl)")
  20. private void matchClassFromPackage() {
  21. }
  22. @Before("matchClassName()")
  23. public void beforeMatchClassName() {
  24. System.out.println("--------精确匹配类名-------");
  25. }
  26. @Before("matchAllClassFromPackage()")
  27. public void beforeMatchAllClassFormPackage() {
  28. System.out.println("--------模糊匹配包中所有的类-------");
  29. }
  30. @Before("matchClassFromPackage()")
  31. public void beforeMatchClassFromPackage() {
  32. System.out.println("--------模糊匹配包中所有的带Impl后缀的-------");
  33. }
  34. }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

# 3.2 @within

# a. API说明

拦截被指定注解标注的类

# b. 目录


    
  1. ├── AnnotationWithinMatchProcessor
  2. │ ├── AopAnnotationWithinMatchProcessor.java
  3. │ ├── Log.java
  4. │ ├── Sprite.java
  5. │ └── readme.md
1 2 3 4 5 6

# c. 拦截代码


    
  1. @Log(tag = "SpriteLog")
  2. @Component
  3. public class Sprite {
  4. public void drink() {
  5. System.out.println("空参数");
  6. }
  7. public void drink(Integer age) {
  8. System.out.println("age");
  9. }
  10. public String name() {
  11. return "Sprite.name";
  12. }
  13. public void toCalculate() throws Exception {
  14. System.out.println(0 / 0);
  15. }
  16. }
  17. @Aspect
  18. @Component
  19. public class AopAnnotationWithinMatchProcessor {
  20. /**
  21. * 注意可以将注解,放到参数中,此时@within()会将参数入参名去找到注解的类型
  22. * 凡是被Log标记的类,都会被拦截
  23. *
  24. * @param spriteLog 注解
  25. */
  26. @Before("@within(spriteLog)")
  27. public void beforeAnnotationMatch(Log spriteLog) {
  28. System.out.println("--------拦截被Log修饰类的所有方法" + spriteLog.tag() + "-------");
  29. }
  30. /**
  31. * 返回值
  32. *
  33. * @param value 返回值
  34. * @param spriteLog 注解
  35. */
  36. @AfterReturning(value = "@within(spriteLog)", returning = "value")
  37. public void afterReturningAnnotationMatch(String value, Log spriteLog) {
  38. System.out.println("afterReturningAnnotationMatch返回值:" + value + ",注解:" + spriteLog);
  39. }
  40. /**
  41. * 拦截异常
  42. *
  43. * @param e 异常
  44. * @param spriteLog 拦截日志
  45. */
  46. @AfterThrowing(value = "@within(spriteLog)", throwing = "e")
  47. public void AfterThrowingAnnotationMatch(Exception e, Log spriteLog) {
  48. System.out.println(e.getMessage());
  49. }
  50. }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

# 3.3 this

# a. API说明

拦截指定的类

# b. 目录


    
  1. ├── ThisMatchProcessor
  2. │ ├── AopThisMatchProcessor.java
  3. │ ├── ThisPerson.java
  4. │ └── readme.md
1 2 3 4 5

# c. 拦截代码


    
  1. @Aspect
  2. @Component
  3. public class AopThisMatchProcessor {
  4. @Before(value = "this(ThisPerson)")
  5. public void thisMatch() {
  6. System.out.println("--------------ThisPerson------------");
  7. }
  8. }
1 2 3 4 5 6 7 8 9 10

# 3.4 args

# a. API说明


    
  1. @Component
  2. public class Person {
  3. public String info(String name) {
  4. return "姓名:" + name;
  5. }
  6. public String info(String name, Integer age) {
  7. return "姓名:" + name + ",年龄:" + age;
  8. }
  9. }
1 2 3 4 5 6 7 8 9 10 11

Person类中有两个info方法,但是入参不一样,假如要拦截指定入参的方法时候,就可以使用args

# b. 目录


    
  1. ├── ArgsMatchProcessor
  2. │ ├── AopArgsMatchProcessor.java
  3. │ ├── Person.java
  4. │ └── readme.md
1 2 3 4

# c. 拦截代码

可以看到args 和 within可以通过&&来进行,联合匹配。另外可以通过returning方法指定方法的返回值。但是注意,类型要和要拦截的方法的返回类型匹配。否则会报错。


    
  1. @Aspect
  2. @Component
  3. public class AopArgsMatchProcessor {
  4. @AfterReturning(value = "within(Person) && args(name,age)", returning = "value")
  5. public void beforeArgs(Integer age, String name, String value) {
  6. System.out.println("拦截器逻辑----------------------------");
  7. System.out.println("入参name:" + name);
  8. System.out.println("入参age:" + age);
  9. System.out.println("返回值:" + value);
  10. System.out.println("拦截器逻辑----------------------------");
  11. }
  12. }
1 2 3 4 5 6 7 8 9 10 11 12 13

# 3.5 @annotation

# a. API说明

拦截被指定注解标记的方法。

# b. 目录


    
  1. ├── AnnotationMethodMatchProcessor
  2. │ ├── AopAnnotationMethodMatchProcessor.java
  3. │ ├── LogMethod.java
  4. │ └── Main.java
1 2 3 4 5

# c. 代码


    
  1. @Aspect
  2. @Component
  3. public class AopAnnotationMethodMatchProcessor {
  4. @Before(value = "@annotation(logMethod) && args(args)")
  5. public void annotationMethodMatch(LogMethod logMethod, String args) {
  6. System.out.println("注解方法匹配");
  7. }
  8. }
1 2 3 4 5 6 7 8 9 10

# 3.6 @args

# a. API说明

拦截方法中入参被@args指定注解的方法。

# b. 目录


    
  1. ├── AnnotationArgsMatchProcessor
  2. │ ├── AopAnnotationArgsMatchProcessor.java
  3. │ ├── Apple.java
  4. │ ├── Fruit.java
  5. │ ├── Orange.java
  6. │ └── Teacher.java
1 2 3 4 5 6

# c. 代码

注意当出现以下异常说明aop声明的拦截范围太广泛了,导致了一些不能拦截的类被拦截从而报错了,此时只用缩小拦截的范围即可

Cannot subclass final class org.springframework.boot.autoconfigure.AutoConfigurationPackages$BasePackages
   
1

缩小拦截范围如下使用this拦截指定类型


    
  1. @Aspect
  2. @Component
  3. public class AopAnnotationArgsMatchProcessor {
  4. @Before(value = "@args(fruit) && this(Teacher)")
  5. public void annotationMethodMatch(Fruit fruit) {
  6. System.out.println("拦截被Fruit+tag:"+fruit.tag());
  7. }
  8. }
1 2 3 4 5 6 7 8 9 10

# 3.7 execution

# a. API说明

execution()是最常用的切点函数,其语法如下所示:

execution(<修饰符模式>? <返回类型模式> <方法名模式>(<参数模式>) <异常模式>?) 除了返回类型模式、方法名模式和参数模式外,其它项都是可选的

表达式 说明
execution(public * *(..)) 匹配所有目标类的public方法
execution(* *Test(..)) 匹配目标类所有以To为后缀的方法
execution(spring.learning.Water.(..)) 匹配Water接口所有方法
execution(spring.learning.Water+.(..)) 匹配Water接口以及实现类中所有方法(包括Water接口中没有的方法)
execution(* spring.learning.*(..)) 匹配spring.learning包下所有的类所有方法
execution(* spring.learning..*(..)) 匹配spring.learning包及其子孙包下所有的类所有方法
execution(* spring..*.Dao.find(..)) 匹配包名前缀为spring的任何包下类名后缀为Dao的方法,方法名必须以find为前缀
execution(* info(String,Integer)) 匹配info方法中,第一个参数是String,第二个Integer的方法
execution(* info(String,*))) 匹配info方法中,第一个参数是String,第二个任意类型
execution(* info(String,..))) 匹配info方法中,第一个参数是String,后面任意参数
execution(* info(Object+))) 匹配info方法中,方法拥有一个入参,且入参是Object类型或该类的子类

文章来源: springlearn.blog.csdn.net,作者:西魏陶渊明,版权归原作者所有,如需转载,请联系作者。

原文链接:springlearn.blog.csdn.net/article/details/125858088

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。