首页 > 文章列表 > SpringBoot项目怎么使用aop

SpringBoot项目怎么使用aop

springboot aop
166 2023-05-18

SpringBoot项目怎么使用aop

前言

IOC和AOP是Spring中的两个核心的概念,简单介绍一下我的理解:

IOC:控制反转,就是将以前由我们自己手动创建对象的过程交给了Spring,Spring帮助我们生产对象、管理对象、管理对象和对象之间的依赖关系。降低了代码的耦合度,方便我们后期对项目做维护。举个通俗一点的例子:

正常情况下,我们在家,饿了,自己做饭。

使用IOC情况下,我们在家,饿了,打电话给商家,饭送过来。

IOC就相当于商家,做饭就相当于创建对象。

也就是说正常情况下,当一个类需要调用其他类的方法时,我们手动通过new、工厂或者其他方式创建对象。

使用IOC情况下,我们只需要注入对象即可。

AOP:面向切面(方便)编程,可以对某一类对象进行监督和控制,在调用这类对象方法的前后去调用指定的代码,从而对一个方法进行扩展,从而达到增强模块功能的效果。举个通俗一点的例子:

正常情况下,直接吃饭。

使用AOP情况下,有个保姆关注着,吃饭前帮忙洗手,吃饭后帮忙收拾碗筷。

AOP就相当于保姆,吃饭就相当于带调用具体的方法。

也就是说,当我们想对方法进行补充时,并不去直接修改方法,而是通过AOP去补充。当我们不想补充或者需要更换补充的时候,直接操作AOP即可。

1、Pointcut: 切点,用于定义哪个方法会被拦截,例如 execution(* cn.springcamp.springaop.service..(…))

2、Advice: 拦截到方法后要执行的动作

3、Aspect: 切面,把Pointcut和Advice组合在一起形成一个切面

4、Join Point: 在执行时Pointcut的一个实例

4、Weaver: 实现AOP的框架,例如 AspectJ 或 Spring AOP

一、SpringBoot项目引入AOP依赖

<!--aop-->

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-aop</artifactId>

        </dependency>

启动类加上@EnableAspectJAutoProxy注解,可以省略。因为在AOP的默认配置属性中,spring.aop.auto属性默认是开启的。

也不需要再引入AspectJ依赖了。

二、普通方式

切面类代码:

package com.example.myblog.test;





import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.*;

import org.springframework.stereotype.Component;



@Component

@Aspect

public class AOPTest {

    //定义切入点

    @Pointcut("execution(public * com.example.myblog.test.AOPTestClient.*(..))")

    public void aspectTest(){}



    //前置通知,切入点执行之前执行

    @Before("aspectTest()")

    public void doBefore(JoinPoint joinPoint){

        System.out.println("前置通知");

    }

    //后置通知,切入点执行之后执行

    @After("aspectTest()")

    public void doAfter(JoinPoint joinPoint){

        System.out.println("后置通知");

    }

    //最终通知,,切入点执行之后执行

    @AfterReturning("aspectTest()")

    public void doAfterReturning(JoinPoint joinPoint){

        System.out.println("最终通知");

    }

    //异常通知,切入点抛出异常执行

    @AfterThrowing("aspectTest()")

    public void deAfterThrowing(JoinPoint joinPoint){

        System.out.println("异常通知");

    }

    //环绕通知,切入点执行前、后执行

    @Around("aspectTest()")

    public Object deAround(ProceedingJoinPoint joinPoint) throws Throwable{

        System.out.println("未执行");

        Object result = joinPoint.proceed();

        System.out.println("已执行");

        //返回结果

        return result;

    }

}

切点类代码:

package com.example.myblog.test;



import org.springframework.stereotype.Component;



@Component

public class AOPTestClient {

    public void test(){

        System.out.println("正在测试AOP");

    }

}

测试类代码:

package com.example.myblog;



import com.example.myblog.test.*;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;



@SpringBootTest

@RunWith(SpringJUnit4ClassRunner.class)

public class MyblogApplicationTests {

    

    @Autowired

    private AOPTestClient aopTestClient;



    @Test

    public void testAOP(){

        aopTestClient.test();

    }

}

测试结果:

三、注解方式

自定义注解代码:

package com.example.myblog.test;



import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;



//表示次注解可以标注在类和方法上

@Target({ElementType.METHOD, ElementType.TYPE})

//运行时生效

@Retention(RetentionPolicy.RUNTIME)

public @interface MyAnnotation {

    //定义一个变量,可以接受参数

    String desc() default " ";

}

切面类代码:

package com.example.myblog.test;



import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.*;

import org.springframework.stereotype.Component;



@Component

@Aspect

public class AOPAnnotationTest {

    //定义切入点

    @Pointcut("@annotation(com.example.myblog.test.MyAnnotation)")

    public void aspectTest(){}



    //前置通知,切入点执行之前执行

    @Before("aspectTest()")

    public void doBefore(JoinPoint joinPoint){

        System.out.println("前置通知");

    }

    //后置通知,切入点执行之后执行

    @After("aspectTest()")

    public void doAfter(JoinPoint joinPoint){

        System.out.println("后置通知");

    }

    //最终通知,,切入点执行之后执行

    @AfterReturning("aspectTest()")

    public void doAfterReturning(JoinPoint joinPoint){

        System.out.println("最终通知");

    }

    //异常通知,切入点抛出异常执行

    @AfterThrowing("aspectTest()")

    public void deAfterThrowing(JoinPoint joinPoint){

        System.out.println("异常通知");

    }

    //环绕通知,切入点执行前、后执行

    @Around("aspectTest()")

    public Object deAround(ProceedingJoinPoint joinPoint) throws Throwable{

        System.out.println("未执行");

        Object result = joinPoint.proceed();

        System.out.println("已执行");

        //返回结果

        return result;

    }

}

切点类代码:

package com.example.myblog.test;



import org.springframework.stereotype.Component;



@Component

public class AOPAnnotationTestClient {

    @MyAnnotation

    public void test(){

        System.out.println("正在测试AOP");

    }

}

测试类代码:

@Test

    public void testAOPAnnotation(){

        aopAnnotationTestClient.test();

    }

测试结果: