Spring AOP自定义注解并获取注解的参数

环境

springboot:1.5
Intellij IDEA:2021.1

序言

最近有个需求,要做方法层面的权限控制。以前在公司使用的是spring security,然后使用注解
如下:

@PreAuthorize("hasPermission('', 'user:login')")
public String helloAdmin() {
    return "I am Admin";
}

但是目前这个项目,虽然引入了spring security的依赖,但是在启动类中排出掉了;
我若开启,势必会要添加很多配置:URL放行、跨域问题等问题。
项目时间赶,没时间去弄。所以选择AOP自定义注解的方式来解决。

步骤

依赖

以下依赖的基础是,项目是springboot的项目:

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

自定义注解

我自定义了一个TestAnnotation注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TestAnnotation {
    String[] values();
}

连接点

其实就是方法。类中所有的方法,都是一个一个的连接点。
当具体到某个方法时,就变成切点

所以连接点仅仅只是个概念。

定义切点

切点:当明确类中某个方法需要被AOP时,那么这个方法就是切点。

切点有两种写法:
① 表达式写法
②注解写法

我们先创建一个TestAspect类:

@Aspect
@Component
public class TestAspect {
	// 这里面写切点和切面
}

表达式的写法

@Aspect
@Component
public class TestAspect {
	@Pointcut("execution(* com.sgy.service.impl..*.*(..)) || execution(* com.sgy.domain..*.*(..))")
	public void action() {
	}
}

注解的写法

@Aspect
@Component
public class TestAspect {

    @Pointcut("@annotation(com.sgy.securitydemo.annotation.TestAnnotation)")
    public void action() {
		//这个空方法就是为了挂切点
    }
}

定义切面

切面就是通知+切点;

想实现的功能、什么时候去做,在哪里做;

@Aspect
@Component
public class TestAspect {

    @Pointcut("@annotation(com.sgy.securitydemo.annotation.TestAnnotation)")
    public void action() {

    }
	//在目标方法被调用之前执行
	//目标方法:被@TestAnnotation注解的方法即为目标方法
	//@annotation中的值,需要和target方法中参数名称相同(必须相同,但是名称任意)
    @Before("@annotation(testAnnotation)")
    public void target(JoinPoint joinPoint, TestAnnotation testAnnotation) {
        System.out.println(Arrays.toString(testAnnotation.values()));
    }
    //写法二:
    //也有这种写法:就是在@Before里面加入切点的空方法,其实没有必要。
    @Before("action() && @annotation(testAnnotation)")
    public void target(JoinPoint joinPoint, TestAnnotation testAnnotation) {
        System.out.println(Arrays.toString(testAnnotation.values()));
    }
	
	//写法三:
	@Before("action()")
    public void target(JoinPoint joinPoint) {
        MethodSignature sign =  (MethodSignature)joinPoint.getSignature();
        Method method = sign.getMethod();
        TestAnnotation testAnnotation = method.getAnnotation(TestAnnotation.class);
        System.out.print("打印:"+ Arrays.toString(testAnnotation.values()) +" 前置日志");
    }
}

注意:

Spring AOP自定义注解并获取注解的参数_第1张图片

使用

@RestController
public class HelloController {
    @GetMapping("/hellono")
    @TestAnnotation(values = "{1,2,3}")
    public String hellono() {
        return "I am Admin";
    }
}

执行结果:

Spring AOP自定义注解并获取注解的参数_第2张图片

其他概念:

引入

就是把切面用到目标类中;所以它只是个概念,具体框架已经帮我们做了。

目标

切点作用的地方。也就是具体某个方法。

织入

把切面应用到目标对象来创建新的代理对象的过程。

遇到的问题

ProceedingJoinPoint as first parameter is allowed only in @Around advices

下面参数中:ProceedingJoinPoint会报错,因为ProceedingJoinPoint只是给@Around用的。

@Before("action()")
public void target(ProceedingJoinPoint joinPoint) {
    MethodSignature sign =  (MethodSignature)joinPoint.getSignature();
    Method method = sign.getMethod();
    TestAnnotation testAnnotation = method.getAnnotation(TestAnnotation.class);
    System.out.print("打印:"+ Arrays.toString(testAnnotation.values()) +" 前置日志");
}

总结

  1. 我想用AOP实现什么样的功能;-- 通知
  2. 我要对哪个方法进行处理; – 切点
  3. 将通知和切换整合起来 – 切面
  4. 定义切面类(@Aspect标注的类)时,记得注入给spring,所以@Component别忘了。

参考地址:

AOP中获取自定义注解的参数值

springboot-自定义注解

Spring AOP与自定义注解Annotation的使用

你可能感兴趣的:(aop,spring,springboot,aop,spring,boot,spring)