我来详细介绍一下 Java 后端自定义注解的创建和使用。
1. 注解的基本概念
注解(Annotation)是 Java 提供的一种元数据机制,用于为代码添加信息。
2. 创建自定义注解
2.1 基本注解定义
import java.lang.annotation.*;
// 元注解:定义注解的生命周期和目标
@Target(ElementType.METHOD) // 注解可以用在方法上
@Retention(RetentionPolicy.RUNTIME) // 注解在运行时保留
@Documented // 包含在 JavaDoc 中
public @interface LogAnnotation {
String value() default ""; // 注解属性
String module() default ""; // 模块名称
String operation() default ""; // 操作类型
}
2.2 常用元注解
-
@Target:指定注解的使用范围ElementType.METHOD:方法ElementType.TYPE:类、接口ElementType.FIELD:字段ElementType.PARAMETER:参数
-
@Retention:指定注解的保留策略RetentionPolicy.SOURCE:仅源码级别RetentionPolicy.CLASS:编译期保留RetentionPolicy.RUNTIME:运行时保留(可通过反射获取)
3. 常用自定义注解示例
3.1 日志注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OperateLog {
String module() default "";
String type() default "";
String desc() default "";
}
3.2 权限注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequirePermission {
String[] value(); // 需要的权限数组
Logical logical() default Logical.AND; // 权限逻辑:AND 或 OR
}
// 权限逻辑枚举
enum Logical {
AND, OR
}
3.3 缓存注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cacheable {
String key(); // 缓存key
long expire() default 300; // 过期时间,默认5分钟
TimeUnit timeUnit() default TimeUnit.SECONDS;
}
3.4 参数校验注解
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface NotEmpty {
String message() default "参数不能为空";
}
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Range {
long min() default Long.MIN_VALUE;
long max() default Long.MAX_VALUE;
String message() default "参数超出范围";
}
3.5 限流注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
String key() default ""; // 限流key
int limit() default 100; // 限制次数
int period() default 60; // 时间周期(秒)
String message() default "系统繁忙,请稍后再试";
}
4. 注解处理器
4.1 AOP 方式处理注解
@Aspect
@Component
@Slf4j
public class AnnotationAspect {
// 处理日志注解
@Around("@annotation(operateLog)")
public Object handleOperateLog(ProceedingJoinPoint joinPoint, OperateLog operateLog) throws Throwable {
String methodName = joinPoint.getSignature().getName();
String module = operateLog.module();
String type = operateLog.type();
String desc = operateLog.desc();
long startTime = System.currentTimeMillis();
try {
log.info("【操作日志】模块:{},类型:{},方法:{},描述:{}",
module, type, methodName, desc);
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
log.info("【操作完成】方法:{},耗时:{}ms", methodName, (endTime - startTime));
return result;
} catch (Exception e) {
log.error("【操作异常】方法:{},异常:{}", methodName, e.getMessage());
throw e;
}
}
// 处理权限注解
@Around("@annotation(requirePermission)")
public Object checkPermission(ProceedingJoinPoint joinPoint, RequirePermission requirePermission) throws Throwable {
String[] permissions = requirePermission.value();
Logical logical = requirePermission.logical();
// 获取当前用户权限(从Session、Token等)
Set<String> userPermissions = getCurrentUserPermissions();
boolean hasPermission;
if (logical == Logical.AND) {
// 需要拥有所有权限
hasPermission = Arrays.stream(permissions)
.allMatch(userPermissions::contains);
} else {
// 只需要拥有其中一个权限
hasPermission = Arrays.stream(permissions)
.anyMatch(userPermissions::contains);
}
if (!hasPermission) {
throw new RuntimeException("权限不足");
}
return joinPoint.proceed();
}
// 处理限流注解
@Around("@annotation(rateLimit)")
public Object handleRateLimit(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {
String key = rateLimit.key();
int limit = rateLimit.limit();
int period = rateLimit.period();
// 使用Redis实现限流
String redisKey = "rate_limit:" + key;
Long current = redisTemplate.opsForValue().increment(redisKey, 1);
if (current == 1) {
// 第一次设置过期时间
redisTemplate.expire(redisKey, period, TimeUnit.SECONDS);
}
if (current > limit) {
throw new RuntimeException(rateLimit.message());
}
return joinPoint.proceed();
}
private Set<String> getCurrentUserPermissions() {
// 实现获取当前用户权限的逻辑
return new HashSet<>();
}
@Autowired
private RedisTemplate<String, Object> redisTemplate;
}
4.2 拦截器方式处理注解
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
// 检查权限注解
if (method.isAnnotationPresent(RequirePermission.class)) {
RequirePermission annotation = method.getAnnotation(RequirePermission.class);
String[] permissions = annotation.value();
// 权限校验逻辑
if (!checkPermissions(permissions)) {
response.setStatus(403);
response.getWriter().write("权限不足");
return false;
}
}
// 检查其他注解...
return true;
}
private boolean checkPermissions(String[] requiredPermissions) {
// 实现权限检查逻辑
return true;
}
}
5. 实际使用示例
5.1 在 Controller 中使用
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/create")
@RequirePermission({"user:create"})
@OperateLog(module = "用户管理", type = "新增", desc = "创建用户")
@RateLimit(key = "user_create", limit = 10, period = 60)
public Result createUser(@RequestBody @Valid UserDTO userDTO) {
return Result.success(userService.createUser(userDTO));
}
@GetMapping("/{id}")
@RequirePermission({"user:query"})
@Cacheable(key = "'user:' + #id", expire = 600)
public Result getUser(@PathVariable Long id) {
return Result.success(userService.getUserById(id));
}
@PutMapping("/{id}")
@RequirePermission({"user:update"})
@OperateLog(module = "用户管理", type = "修改", desc = "更新用户信息")
public Result updateUser(@PathVariable Long id, @RequestBody UserDTO userDTO) {
return Result.success(userService.updateUser(id, userDTO));
}
@DeleteMapping("/{id}")
@RequirePermission({"user:delete"})
@OperateLog(module = "用户管理", type = "删除", desc = "删除用户")
public Result deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return Result.success();
}
}
5.2 在 Service 中使用
@Service
@Slf4j
public class UserService {
@Autowired
private UserMapper userMapper;
@OperateLog(module = "用户服务", type = "业务操作", desc = "创建用户")
public User createUser(UserDTO userDTO) {
// 业务逻辑
User user = convertToUser(userDTO);
userMapper.insert(user);
return user;
}
@Cacheable(key = "'user:' + #id", expire = 600)
public User getUserById(Long id) {
return userMapper.selectById(id);
}
}
6. 配置类
6.1 AOP 配置
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
}
6.2 拦截器配置
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login", "/register");
}
}
7. 总结
自定义注解在 Java 后端开发中非常有用,可以用于:
- 日志记录:自动记录操作日志
- 权限控制:统一权限校验
- 缓存管理:自动缓存方法结果
- 参数校验:自定义参数验证规则
- 限流控制:接口访问频率限制
- 事务管理:自定义事务控制
- 数据脱敏:自动处理敏感信息
1208

被折叠的 条评论
为什么被折叠?



