AOP 使用指南
【摘要】
作者: 西魏陶渊明
博客: 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说明
- 精确匹配类名
- 模糊匹配包中所有的类
- 模糊匹配包中所有的带Impl后缀的
# b. 目录
-
└── WithinMatchProcessor
-
├── AopWithinMatchProcessor.java
-
├── CokeImpl.java
-
├── Water.java
-
└── readme.md
1 2 3 4 5
# c. 拦截代码
-
@Aspect
-
@Component
-
public class AopWithinMatchProcessor {
-
-
/**
-
* 精确匹配类名
-
*/
-
@Pointcut("within(spring.learning.aop.WithinMatchProcessor.Water)")
-
private void matchClassName() {
-
}
-
-
/**
-
* 模糊匹配包中所有的类
-
*/
-
@Pointcut("within(spring.learning.aop.WithinMatchProcessor.*)")
-
private void matchAllClassFromPackage() {
-
}
-
-
/**
-
* 模糊匹配包中所有的带Impl后缀的
-
*/
-
@Pointcut("within(spring.learning.aop.WithinMatchProcessor.*Impl)")
-
private void matchClassFromPackage() {
-
}
-
-
-
@Before("matchClassName()")
-
public void beforeMatchClassName() {
-
System.out.println("--------精确匹配类名-------");
-
}
-
-
@Before("matchAllClassFromPackage()")
-
public void beforeMatchAllClassFormPackage() {
-
System.out.println("--------模糊匹配包中所有的类-------");
-
}
-
-
@Before("matchClassFromPackage()")
-
public void beforeMatchClassFromPackage() {
-
System.out.println("--------模糊匹配包中所有的带Impl后缀的-------");
-
}
-
-
-
}
-
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. 目录
-
├── AnnotationWithinMatchProcessor
-
│ ├── AopAnnotationWithinMatchProcessor.java
-
│ ├── Log.java
-
│ ├── Sprite.java
-
│ └── readme.md
1 2 3 4 5 6
# c. 拦截代码
-
@Log(tag = "SpriteLog")
-
@Component
-
public class Sprite {
-
-
public void drink() {
-
System.out.println("空参数");
-
}
-
-
public void drink(Integer age) {
-
System.out.println("age");
-
}
-
-
-
public String name() {
-
return "Sprite.name";
-
}
-
-
public void toCalculate() throws Exception {
-
System.out.println(0 / 0);
-
}
-
}
-
-
@Aspect
-
@Component
-
public class AopAnnotationWithinMatchProcessor {
-
-
-
/**
-
* 注意可以将注解,放到参数中,此时@within()会将参数入参名去找到注解的类型
-
* 凡是被Log标记的类,都会被拦截
-
*
-
* @param spriteLog 注解
-
*/
-
@Before("@within(spriteLog)")
-
public void beforeAnnotationMatch(Log spriteLog) {
-
System.out.println("--------拦截被Log修饰类的所有方法" + spriteLog.tag() + "-------");
-
}
-
-
-
/**
-
* 返回值
-
*
-
* @param value 返回值
-
* @param spriteLog 注解
-
*/
-
@AfterReturning(value = "@within(spriteLog)", returning = "value")
-
public void afterReturningAnnotationMatch(String value, Log spriteLog) {
-
System.out.println("afterReturningAnnotationMatch返回值:" + value + ",注解:" + spriteLog);
-
}
-
-
/**
-
* 拦截异常
-
*
-
* @param e 异常
-
* @param spriteLog 拦截日志
-
*/
-
@AfterThrowing(value = "@within(spriteLog)", throwing = "e")
-
public void AfterThrowingAnnotationMatch(Exception e, Log spriteLog) {
-
System.out.println(e.getMessage());
-
}
-
-
}
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. 目录
-
├── ThisMatchProcessor
-
│ ├── AopThisMatchProcessor.java
-
│ ├── ThisPerson.java
-
│ └── readme.md
1 2 3 4 5
# c. 拦截代码
-
@Aspect
-
@Component
-
public class AopThisMatchProcessor {
-
-
@Before(value = "this(ThisPerson)")
-
public void thisMatch() {
-
System.out.println("--------------ThisPerson------------");
-
}
-
}
-
1 2 3 4 5 6 7 8 9 10
# 3.4 args
# a. API说明
-
@Component
-
public class Person {
-
-
public String info(String name) {
-
return "姓名:" + name;
-
}
-
-
public String info(String name, Integer age) {
-
return "姓名:" + name + ",年龄:" + age;
-
}
-
}
1 2 3 4 5 6 7 8 9 10 11
Person类中有两个info方法,但是入参不一样,假如要拦截指定入参的方法时候,就可以使用args
# b. 目录
-
├── ArgsMatchProcessor
-
│ ├── AopArgsMatchProcessor.java
-
│ ├── Person.java
-
│ └── readme.md
1 2 3 4
# c. 拦截代码
可以看到args 和 within可以通过&&来进行,联合匹配。另外可以通过returning方法指定方法的返回值。但是注意,类型要和要拦截的方法的返回类型匹配。否则会报错。
-
@Aspect
-
@Component
-
public class AopArgsMatchProcessor {
-
-
@AfterReturning(value = "within(Person) && args(name,age)", returning = "value")
-
public void beforeArgs(Integer age, String name, String value) {
-
System.out.println("拦截器逻辑----------------------------");
-
System.out.println("入参name:" + name);
-
System.out.println("入参age:" + age);
-
System.out.println("返回值:" + value);
-
System.out.println("拦截器逻辑----------------------------");
-
}
-
}
1 2 3 4 5 6 7 8 9 10 11 12 13
# 3.5 @annotation
# a. API说明
拦截被指定注解标记的方法。
# b. 目录
-
├── AnnotationMethodMatchProcessor
-
│ ├── AopAnnotationMethodMatchProcessor.java
-
│ ├── LogMethod.java
-
│ └── Main.java
1 2 3 4 5
# c. 代码
-
@Aspect
-
@Component
-
public class AopAnnotationMethodMatchProcessor {
-
-
-
@Before(value = "@annotation(logMethod) && args(args)")
-
public void annotationMethodMatch(LogMethod logMethod, String args) {
-
System.out.println("注解方法匹配");
-
}
-
}
1 2 3 4 5 6 7 8 9 10
# 3.6 @args
# a. API说明
拦截方法中入参被@args指定注解的方法。
# b. 目录
-
├── AnnotationArgsMatchProcessor
-
│ ├── AopAnnotationArgsMatchProcessor.java
-
│ ├── Apple.java
-
│ ├── Fruit.java
-
│ ├── Orange.java
-
│ └── Teacher.java
1 2 3 4 5 6
# c. 代码
注意当出现以下异常说明aop声明的拦截范围太广泛了,导致了一些不能拦截的类被拦截从而报错了,此时只用缩小拦截的范围即可
Cannot subclass final class org.springframework.boot.autoconfigure.AutoConfigurationPackages$BasePackages
1
缩小拦截范围如下使用this拦截指定类型
-
@Aspect
-
@Component
-
public class AopAnnotationArgsMatchProcessor {
-
-
@Before(value = "@args(fruit) && this(Teacher)")
-
public void annotationMethodMatch(Fruit fruit) {
-
System.out.println("拦截被Fruit+tag:"+fruit.tag());
-
}
-
}
-
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)