代码改变世界

spring boot aop使用

  youxin  阅读(77)  评论(0编辑  收藏  举报

Spring AOP术语

Spring AOP术语

通知(Advice)包含了需要用于多个应用对象的横切行为,完全听不懂,没关系,通俗一点说就是定义了“什么时候”和“做什么”。

连接点(Join Point)是程序执行过程中能够应用通知的所有点。

切点(Pointcut)是定义了在“什么地方”进行切入,哪些连接点会得到通知。显然,切点一定是连接点。

切面(Aspect)是通知和切点的结合。通知和切点共同定义了切面的全部内容——是什么,何时,何地完成功能。

引入(Introduction)允许我们向现有的类中添加新方法或者属性。

织入(Weaving)是把切面应用到目标对象并创建新的代理对象的过程,分为编译期织入、类加载期织入和运行期织入。

 

 

spring Boot AOP实战

Spring Boot使用AOP需要添加spring-boot-starter-aop依赖,如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

不需要再添加aspectjweaver的依赖了,因为spring-boot-starter-aop包含了aspectjweaver,并且版本是较新的版本,如果在添加老版本(如1.5.4)启动会报错。

编写用于拦截的bean

直接定义一个controller,代码如下:

@RestController
public class AopController {

    @RequestMapping("/hello")
    public String sayHello(){
        System.out.println("hello");
        return "hello";
    }
}

3.3 定义切面

Spring采用@AspectJ注解对POJO进行标注,该注解表明该类不仅仅是一个POJO,还是一个切面。切面是切点和通知的结合,那么定义一个切面就需要编写切点和通知。在代码中,只需要添加@Aspect注解即可。

定义切点

切点是通过@Pointcut注解和切点表达式定义的。

@Pointcut注解可以在一个切面内定义可重用的切点。

由于Spring切面粒度最小是达到方法级别,而execution表达式可以用于明确指定方法返回类型,类名,方法名和参数名等与方法相关的部件,并且实际中,大部分需要使用AOP的业务场景也只需要达到方法级别即可,因而execution表达式的使用是最为广泛的。如图是execution表达式的语法:

execution表示在方法执行的时候触发。以“”开头,表明方法返回值类型为任意类型。然后是全限定的类名和方法名,“”可以表示任意类和任意方法。对于方法参数列表,可以使用“..”表示参数为任意类型。如果需要多个表达式,可以使用“&&”、“||”和“!”完成与、或、非的操作。

切点表达式

 

关于AOP PointCut() 切入点表达式参数的详解
(1)excution表达式
这个定义的是切入点的位置,称为:execution切点函数

分为五个部分:
execution(): 表达式主体;
修饰符: 匹配所有目标类以什么修饰的方法(如:public 方法)
返回值:返回值,通常以* 代替,返回什么类型都可以!
描述包名:表示拦截哪个包(需要写包的全路径),通常会写 .. 表示当前包和当前包的子 包;
类名:表示要拦截的类, * 表示所有类都拦截,或者拦截指定一个类
方法名():表示要拦截的方法, * 表示所有方法都拦截,或者拦截指定一个方法
():方法后边会有括号,里边可以指定拦截的参数,  两个点表示拦截任何参数。
execution(
· 修饰符 —— 可以省略,如果省略,就是所有的修饰符都会被拦截!
· 返回值 —— 必填,方法的返回值
· 描述包名 —— 可省略
· 类名 —— 可省略,如果省略,就是所有的类都会被拦截!
· 方法名(参数)—— 必填
· 方法抛出异常 —— 必填
)
原文链接:https://blog.csdn.net/qq_45905045/article/details/124886104

代码示例:
匹配所有目标类的public方法;
要拦截的包名为:com.lxc.springboot.service包及子孙包下的所有类方法, 两个点表示当前包及以下的子孙包,一个点表示当前的包;
两个点后边的 * 星号表示类名,这里要拦截所有的类;
后边的 .*(…) 表示方法,*星号表示所有的方法,(…) 括号中表示方法参数,两个点表示任何参数。

复制代码
// 定义一个切入点,关于切入点如何定义?
@Pointcut("execution(public * com.lxc.springboot.service..*.*(..))")
public void pointFn(){}
 
// 定义一个通知,在执行pointFn这个方法之前(切入入进去之前),我们需要执行check方法
@Before("pointFn()")
public void check() {
    System.out.println("check"); // 前置通知
}
复制代码

 

包名可以使用通配符,表示任意包,但是有几级包,就需要写几个*.

* *.*.*.*.HelloController.helloAop()
1
包名可以使用...表示当前包及其子包

* *...HelloController.helloAop()
1
类名和方法名都可以使用*来实现通配

* *..*.*()
1
表达式中的参数列表,可以直接写数据类型:

基本类型直接写名称 :例如,int
引用类型写包名.类名的方式 :例如,java.lang.String
可以使用通配符*表示任意类型,但是必须有参数
可以使用…表示有无参数均可,有参数可以是任意类型
全通配写法:* *..*.*(...)

within表达式
是用来指定类型的,指定类型中的所有方法将被拦截

表达式:包名.包名.包名…类名

标准的表达式写法范例:

com.aismall.testaop.controller.HelloController
1
举例:匹配HelloController类对应对象的所有方法,并且只能是HelloController类生成的对象,不能是它的子类生成的对象。

within(com.aismall.testaop.controller.HelloController)
1
也可以使用通配符*:匹配com.aismall包及其子包下面的所有类的所有方法。

within(com.aismall…*)

 

 

 

定义通知

通知有五种类型,分别是:

前置通知(@Before):在目标方法调用之前调用通知

后置通知(@After):在目标方法完成之后调用通知

环绕通知(@Around):在被通知的方法调用之前和调用之后执行自定义的方法

返回通知(@AfterReturning):在目标方法成功执行之后调用通知

异常通知(@AfterThrowing):在目标方法抛出异常之后调用通知

代码中定义了三种类型的通知,使用@Before注解标识前置通知,打印“beforeAdvice...”,使用@After注解标识后置通知,打印“AfterAdvice...”,使用@Around注解标识环绕通知,在方法执行前和执行之后分别打印“before”和“after”。这样一个切面就定义好了,代码如下:

复制代码
@Aspect
@Component
public class AopAdvice {

    @Pointcut("execution (* com.shangguan.aop.controller.*.*(..))")
    public void test() {

    }

    @Before("test()")
    public void beforeAdvice() {
        System.out.println("beforeAdvice...");
    }

    @After("test()")
    public void afterAdvice() {
        System.out.println("afterAdvice...");
    }

    @Around("test()")
    public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println("before");
        try {
            proceedingJoinPoint.proceed();
        } catch (Throwable t) {
            t.printStackTrace();
        }
        System.out.println("after");
    }

}
 
复制代码

 

Spring aop报错Pointcut is not well-formed: expecting ‘(‘ at character position 0

根据报错是说我的切面方法没有括号().解决方法:把切面类中的@Before("matchArgs()")修改成@Before("matchArgs()")就可以了。代码如下:

 

相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
历史上的今天:
2022-03-18 Robot Framework 自动化测试框架
2014-03-18 Linux 统计文件夹下文件个数
2013-03-18 jquery选择器返回数组处理
2013-03-18 LR分析
2013-03-18 eclipse打开当前文件所在文件夹的两种方法
2013-03-18 编译原理---递归下降分析法
2012-03-18 c++ string::size详解
点击右上角即可分享
微信分享提示