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()) +" 前置日志");
}
}
注意:
@RestController
public class HelloController {
@GetMapping("/hellono")
@TestAnnotation(values = "{1,2,3}")
public String hellono() {
return "I am Admin";
}
}
执行结果:
其他概念:
就是把切面用到目标类中;所以它只是个概念,具体框架已经帮我们做了。
切点作用的地方。也就是具体某个方法。
把切面应用到目标对象来创建新的代理对象的过程。
下面参数中: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()) +" 前置日志");
}
@Aspect
标注的类)时,记得注入给spring
,所以@Component
别忘了。参考地址:
AOP中获取自定义注解的参数值
springboot-自定义注解
Spring AOP与自定义注解Annotation的使用