SpringBoot面向切面编程(AOP)

SpringBoot面向切面编程(AOP)

gitee地址:SpringBoot面向切面编程

1.目录结构

SpringBoot面向切面编程(AOP)

2.依赖

    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.1.0.RELEASE</version>
    </parent>

    <dependencies>
        <!--测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <!--切面依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
    </dependencies>

3.service

public interface ExampleService {

    String findAll(String name);

    boolean save();

    boolean update();

    boolean delete();
}
import com.qq.annotation.Sign;
import com.qq.service.ExampleService;
import org.springframework.stereotype.Service;

/**
 * @author 黔程似景
 * @description 业务代码
 * @date 2021/12/5 9:55
 **/
@Service
public class ExampleServiceImpl implements ExampleService {

    @Override
    public String findAll(String name) {
        System.out.println("---------------------所有数据-------------------------");
        return name;
    }

    @Sign
    @Override
    public boolean save() {
        System.out.println("---------------------保存成功-------------------------");
        return true;
    }

    @Override
    public boolean update() {
        System.out.println("---------------------修改成功-------------------------");
        return true;
    }

    @Override
    public boolean delete() {
        System.out.println("---------------------删除成功-------------------------");
        return true;
    }
}

4.注解

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 Sign {
}

5.aop配置文件

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @author 黔程似景
 * @description 切面类
 * @date 2021/12/5 9:58
 **/
@Aspect  // 标注此类为切面类
@Component
public class AopConfig {

    /**
     * 切入点
     */
    @Pointcut("@annotation(com.qq.annotation.Sign) || execution(* com.qq.service..*.find*(..))")
    public void pointcut(){
    }

    /**
     * 前置通知:在执行方法前执行
     */
    @Before(value = "pointcut()")
    public void before(JoinPoint joinPoint){
        System.out.println("--------------前置通知-----------------");
        Signature signature = joinPoint.getSignature();
        System.out.println("获取方法:"+signature);
        Object[] args = joinPoint.getArgs();
        System.out.println("获取传入参数:"+Arrays.toString(args));
    }

    /**
     * 异常通知:在执行方法出现异常时执行
     */
    @AfterThrowing(value = "pointcut()")
    public void afterThrow(JoinPoint joinPoint){
        System.out.println("--------------异常通知------------------");
        System.out.println("异常方法:"+joinPoint.getSignature());
    }

    /**
     * 后置通知:在执行方法后执行,无论是否出现异常,则都会执行
     */
    @After(value = "pointcut()")
    public void after(){
        System.out.println("---------------后置通知-----------------");
    }

    /**
     * 最终通知:当出现异常,则不会执行
     */
    @AfterReturning(value = "pointcut()" , returning = "result")
    public void afterReturning(Object result){
        System.out.println("目标方法返回值:"+result);
    }

//    /**
//     * 环绕通知(包含前置通知,后置通知,异常通知,最终通知)
//     * 执行顺序:前置通知--->后置通知(异常通知)--->最终通知
//     * @param joinPoint
//     * @return
//     */
//    @Around(value = "pointcut()")
//    public Object around(ProceedingJoinPoint joinPoint) {
//
//        Object rvt = null;//不改变参数
//        try {
//            System.out.println("----------------前置通知------------------");
//            rvt = joinPoint.proceed();
        Object rvt = jp.proceed(new String[] { "被改变的参数" });
//            System.out.println("----------------后置通知------------------");
//        } catch (Throwable throwable) {
//            System.out.println("----------------异常通知------------------");
//            throwable.printStackTrace();
//        }finally {
//            System.out.println("----------------最终通知------------------");
//        }
//
//        return rvt + " 新增的内容";
//    }

}

6.启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AopApplication {
    public static void main(String[] args) {
        SpringApplication.run(AopApplication.class, args);
    }
}

7.测试类

import com.qq.service.ExampleService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

/**
 * @author 黔程似景
 * @description 测试类
 * @date 2021/12/5 10:03
 **/
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestExampleService {

    @Resource
    public ExampleService exampleService;

    /**
     * 切面测试
     */
    @Test
    public void test() {
        exampleService.findAll("法外狂徒");
        System.out.println("\n\n\n");
        exampleService.save();
        System.out.println("\n\n\n");
        exampleService.update();
    }

}

8.执行结果

SpringBoot面向切面编程(AOP)

9.了解内容:切点函数于表达式语法

切入点函数 作用
execution 细粒度函数,精确到方法
within 粗粒度,只能精确到类
bean 粗粒度,精确到类,从容器中通过id获取对象
@annotation 包含注解的所有类和方法

execution表达式语法

execution(* *(..))
匹配所有的类和方法

!execution(* save(..))
除了方法名是save的所有方法

方法参数设置:
()  没有参数
(*) 1个或多个参数
(..) 0个或多个参数
例如:find()----->无参方法
execution(* save(..)) || execution(* update(..))
匹配方法名是save或update的方法

within表达式语法

within(com.qq..*)
匹配包和子包中所有的类

bean表达式语法

bean(exampleService)
从容器中获取一个id为accountService的类中所有方法
bean(*Service) 
从容器中获取所有Service的方法

注解表达式语法

@annotation(com.qq.annotation.Sign)
匹配包含注解的所有类和方法
上一篇:06--Spring5 AOP(底层原理)


下一篇:C# 关于AOP简单介绍