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

7 篇文章 0 订阅
3 篇文章 0 订阅

环境

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.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</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()) +" 前置日志");
    }
}

注意:

在这里插入图片描述

使用

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

执行结果:

在这里插入图片描述

其他概念:

引入

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

目标

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

织入

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

遇到的问题

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的使用

  • 13
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
要实现 AOP 自定义注解获取实体入参,可以按照以下步骤进行: 1. 定义注解:定义一个注解,用于标记需要被 AOP 拦截的方法。 2. 编写切面:编写一个切面,用于拦截被注解标记的方法,并获取方法的参数。 3. 获取实体入参:在切面中获取方法的参数,通过反射的方式获得实体入参。 下面是一个示例代码,假设我们需要获取被 @LogAnnotation 注解标记的方法的实体入参: 定义注解: ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface LogAnnotation { String value() default ""; } ``` 编写切面: ```java @Component @Aspect public class LogAspect { @Around("@annotation(com.example.demo.annotation.LogAnnotation)") public Object around(ProceedingJoinPoint pjp) throws Throwable { // 获取方法参数 Object[] args = pjp.getArgs(); // 判断参数是否为实体类 for (Object arg : args) { if (arg instanceof BaseEntity) { // 获取实体入参 BaseEntity entity = (BaseEntity) arg; // TODO: 处理实体入参 } } // 执行方法 Object result = pjp.proceed(); return result; } } ``` 在上面的代码中,我们使用 @Around 注解标记了 around 方法,并指定了切点表达式 @annotation(com.example.demo.annotation.LogAnnotation),表示拦截被 @LogAnnotation 注解标记的方法。在 around 方法中,通过 ProceedingJoinPoint 对象获取方法的参数,然后判断参数是否为实体类,如果是实体类,则获取实体入参,进行处理。 注意,在获取实体入参时,我们使用了 instanceof 判断参数是否为实体类,因此需要保证实体类继承了一个 BaseEntity 类或接口,否则无法判断参数是否为实体类。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山鬼谣me

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值