Spring自定义AOP

我们在学习Spring的时候,总是会看到Spring对于AOP的支持,这同IOC一起,属于Spring的两大核心。既然是核心,这AOP又有哪些应用场景呢?
相信很多小伙伴都知道:权限控制、事务管理、记录日志等。
那么基于这些应用场景,我们如何去自定义满足场景业务的AOP呢?
好的,咱们废话少说,直接开撸!

AOP的组成

首先我们来看看,自定义一个最简单的AOP,需要哪些步骤
1、定义切面类Aspect:所有有关切面的操作实现都可以在这个类中完成;
2、寻找切入点Pointcut:根据自己的场景业务及代码结构,寻找合适的切入点,在这个切入点前后,我们会加入自定义的增强操作;
3、增强处理Advice:所谓增强处理,就是具体的场景业务实现,可以是调用方法之前的权限判断,可以是执行方法前后的事务处理,也可以是执行某项操作后的日志记录。

自定义AOP实现

准备工作,需要先加入AOP的pom引用,,如果是Spring Boot的开发者可以使用下面的引用方式

		<dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-aopartifactId>
        dependency>

这是Spring Boot已经封装好的,实际上最终引用的是org.aspectj的包
Spring自定义AOP_第1张图片
接下来就是激动人心的开发环节

1、定义切面类

按照刚刚介绍的步骤,首先我们需要定义一个切面类,这很简单,只需要在创建的类名上加上@Aspect注解就可以了,需要注意的是引用的包名org.aspectj.lang.annotation.*
Spring自定义AOP_第2张图片

2、寻找切入点

第二步就是根据自己的场景业务,寻找一个切入点。
比如说:我需要记录用户表User的操作日志,那么我这里就可以将所有有关用户表的增删查改当作切入点,而对于用户的所有操作方法,我都是写在UserService里面,所以切入点选他就完事儿了。
然后通过@Pointcut注解来选中刚刚我们分析得来的切入点,具体写法,就可以像下面这样写
Spring自定义AOP_第3张图片
当然,切入点的匹配方式还有很多种,可以根据自己的业务自行选择:

  • execution:用于匹配方法执行的连接点;
  • this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
  • within:用于匹配指定类型内的方法执行;
  • @within:用于匹配所以持有指定注解类型内的方法;
  • target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
  • @target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
  • args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;
  • @args:用于匹配当前执行的方法传入的参数持有指定注解的执行;
  • @annotation:用于匹配当前执行方法持有指定注解的方法。
3、增强处理

最后一步,就是定义增强处理来完成场景业务逻辑。增强方式也有很多种,我们这里选择“前置增强@Before”和“后置增强@After”,然后在增强方法里面控制台打印调用的方法和方法传参
Spring自定义AOP_第4张图片

到这一步我们的自定义AOP就算完成了,运行一下单元测试,看看控制台打印结果
Spring自定义AOP_第5张图片

切面类完整代码如下

package com.jorkeycloud.integration.aop;

import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * 自定义切面
 * @author Jorkey
 * @version v1.0
 **/
@Aspect
@Component
public class DiyAspect {

    @Pointcut("this(com.jorkeycloud.integration.service.UserService)")
    public void diyPointCut(){}

    @Before("diyPointCut()")
    public void beforeCut(JoinPoint joinPoint) {
        // 打印调用的方法名称
        System.err.println("method name: "+joinPoint.getSignature().getName());
        System.err.println("method args: ");
        Arrays.stream(joinPoint.getArgs()).forEach(arg -> {
            // 循环打印所有方法参数
            System.err.println(JSONObject.toJSONString(arg));
        });
        System.err.println("----====---->前置增强");
    }

    @After("diyPointCut()")
    public void afterCut(JoinPoint joinPoint) {
        System.err.println("----====---->后置增强");
    }
}

以上demo仅供参考,如有说的不对的地方,欢迎下方评论区讨论 (^ _ ^)

你可能感兴趣的:(Spring,spring,java,spring,boot)