您好,登录后才能下订单哦!
# Spring如何实现重复注解和AOP拦截
## 目录
1. [重复注解的背景与需求](#重复注解的背景与需求)
2. [Java 8的重复注解机制](#java-8的重复注解机制)
3. [Spring对重复注解的支持](#spring对重复注解的支持)
4. [AOP拦截重复注解的实现](#aop拦截重复注解的实现)
5. [完整代码示例](#完整代码示例)
6. [实际应用场景](#实际应用场景)
7. [总结](#总结)
---
## 重复注解的背景与需求
在Java 8之前,注解(Annotation)在同一个位置只能声明一次。这种限制在某些场景下会带来不便,例如:
```java
// Java 8前无法这样声明多个相同注解
@Permission(role="admin")
@Permission(role="manager")
public void sensitiveOperation() {}
Java 8通过重复注解机制解决了这个问题,允许在同一个元素上多次使用相同的注解。
Java 8通过两个关键要素实现重复注解:
// 1. 定义可重复注解
@Repeatable(Permissions.class) // 指定容器注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Permission {
String role();
}
// 2. 定义容器注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Permissions {
Permission[] value(); // 必须命名为value
}
使用示例:
@Permission(role="admin")
@Permission(role="auditor")
public void adminOperation() {}
Spring框架从4.0版本开始全面支持Java 8特性,包括重复注解。核心支持体现在:
AnnotatedElementUtils
工具类获取重复注解的Spring方式:
Set<Permission> permissions = AnnotatedElementUtils
.getMergedRepeatableAnnotations(
method, Permission.class, Permissions.class);
与Java原生API的区别:
方式 | 特点 |
---|---|
getAnnotationsByType() |
Java原生,只处理直接注解 |
getMergedRepeatableAnnotations() |
Spring增强,支持继承、接口等 |
@Aspect
@Component
public class PermissionAspect {
@Before("@annotation(permission)")
public void checkPermission(Permission permission) {
// 单注解处理逻辑
}
}
方案一:拦截容器注解
@Before("@annotation(permissions)")
public void checkPermissions(Permissions permissions) {
for (Permission p : permissions.value()) {
checkSinglePermission(p);
}
}
方案二:使用Spring工具类增强
@Before("execution(* com.example..*(..))")
public void checkPermissions(JoinPoint jp) {
Method method = ((MethodSignature) jp.getSignature()).getMethod();
Set<Permission> permissions = AnnotatedElementUtils
.getMergedRepeatableAnnotations(method, Permission.class, Permissions.class);
permissions.forEach(this::checkSinglePermission);
}
@Around
替代多次@Before
减少代理调用// Permission.java
@Repeatable(Permissions.class)
@Retention(RUNTIME)
@Target(METHOD)
public @interface Permission {
String value();
String action() default "read";
}
// Permissions.java
@Retention(RUNTIME)
@Target(METHOD)
public @interface Permissions {
Permission[] value();
}
@Aspect
@Component
public class SecurityAspect {
private static final Logger log = LoggerFactory.getLogger(SecurityAspect.class);
@Around("@within(org.springframework.stereotype.Controller) || " +
"@within(org.springframework.web.bind.annotation.RestController)")
public Object checkApiPermission(ProceedingJoinPoint pjp) throws Throwable {
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
// 获取所有Permission注解(包括重复注解)
Set<Permission> permissions = AnnotatedElementUtils
.getMergedRepeatableAnnotations(method, Permission.class, Permissions.class);
if (!permissions.isEmpty()) {
User user = CurrentUser.get();
boolean hasPermission = permissions.stream()
.anyMatch(p -> user.hasPermission(p.value(), p.action()));
if (!hasPermission) {
throw new AccessDeniedException("Permission denied");
}
}
return pjp.proceed();
}
}
@RestController
@RequestMapping("/api")
public class AdminController {
@Permission("user.create")
@PostMapping("/users")
public User createUser(@RequestBody User user) {
// ...
}
@Permission("user.read")
@Permission("audit.read") // 重复注解
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
// ...
}
}
@LogOperation(type="login")
@LogOperation(module="security")
public void login() {...}
@Validate(regex="\\d+")
@Validate(minLength=6)
private String password;
关键技术点:
1. Java 8的@Repeatable
+容器注解机制
2. Spring的AnnotatedElementUtils
工具类
3. AOP中通过容器注解或工具类处理
最佳实践:
✔️ 优先使用Spring工具类处理复杂场景
✔️ 考虑注解继承关系(如接口上的注解)
✔️ 对性能敏感场景添加适当缓存
扩展思考: - 动态注解的可行性(通过APT或运行时字节码增强) - 与其他Spring特性(如SpEL)的整合 - 在响应式编程中的适配问题
通过合理运用重复注解和AOP,可以实现高度可扩展的声明式编程模型,显著提升代码的可读性和维护性。 “`
(注:实际MD文档显示的字数统计可能因渲染环境不同略有差异,本文档核心内容约3100字)
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。