本文目录导读:

我将为您展示一个完整的自定义注解实现案例,包括注解定义、处理器实现以及实际应用。
自定义注解定义
import java.lang.annotation.*;
// 1. 日志注解
@Target(ElementType.METHOD) // 只能用在方法上
@Retention(RetentionPolicy.RUNTIME) // 运行时保留
@Documented // 生成文档
public @interface LogAnnotation {
// 操作类型
String action() default "";
// 操作描述
String description() default "";
// 是否记录参数
boolean recordParams() default true;
// 日志级别
LogLevel level() default LogLevel.INFO;
enum LogLevel {
INFO, WARN, ERROR
}
}
import java.lang.annotation.*;
// 2. 参数校验注解
@Target(ElementType.FIELD) // 用在字段上
@Retention(RetentionPolicy.RUNTIME)
public @interface Validate {
// 是否必填
boolean required() default true;
// 最小长度
int minLength() default 0;
// 最大长度
int maxLength() default Integer.MAX_VALUE;
// 正则表达式
String pattern() default "";
// 错误消息
String message() default "参数校验失败";
}
import java.lang.annotation.*;
// 3. 缓存注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cacheable {
// 缓存key
String key() default "";
// 过期时间(秒)
int expire() default 60;
// 是否缓存空值
boolean cacheNull() default false;
}
注解处理器实现
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.Date;
@Aspect
@Component
public class LogAspect {
private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Around("@annotation(logAnnotation)")
public Object around(ProceedingJoinPoint joinPoint, LogAnnotation logAnnotation) throws Throwable {
// 获取方法签名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String methodName = signature.getMethod().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
// 开始时间
long startTime = System.currentTimeMillis();
// 构建日志信息
StringBuilder logInfo = new StringBuilder();
logInfo.append("\n========== 开始执行 ==========\n");
logInfo.append("操作类名: ").append(className).append("\n");
logInfo.append("操作方法: ").append(methodName).append("\n");
logInfo.append("操作类型: ").append(logAnnotation.action()).append("\n");
logInfo.append("操作描述: ").append(logAnnotation.description()).append("\n");
// 记录参数
if (logAnnotation.recordParams()) {
Object[] args = joinPoint.getArgs();
logInfo.append("方法参数: ").append(Arrays.toString(args)).append("\n");
}
Object result = null;
try {
// 执行原方法
result = joinPoint.proceed();
// 记录执行结果
logInfo.append("执行结果: SUCCESS\n");
logInfo.append("返回结果: ").append(result).append("\n");
// 根据日志级别输出
switch (logAnnotation.level()) {
case ERROR:
logger.error(logInfo.toString());
break;
case WARN:
logger.warn(logInfo.toString());
break;
default:
logger.info(logInfo.toString());
}
} catch (Exception e) {
logInfo.append("执行结果: FAIL\n");
logInfo.append("异常信息: ").append(e.getMessage()).append("\n");
logger.error(logInfo.toString());
throw e;
} finally {
long endTime = System.currentTimeMillis();
logger.info("执行耗时: {} ms", endTime - startTime);
logger.info("========== 结束执行 ==========");
}
return result;
}
}
参数校验处理器
import java.lang.reflect.Field;
import java.util.regex.Pattern;
public class ValidationProcessor {
/**
* 校验对象
*/
public static void validate(Object obj) throws IllegalAccessException, ValidationException {
if (obj == null) {
throw new ValidationException("对象不能为空");
}
Class<?> clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
// 设置字段可访问
field.setAccessible(true);
// 检查是否有Validate注解
Validate annotation = field.getAnnotation(Validate.class);
if (annotation == null) {
continue;
}
Object value = field.get(obj);
// 校验必填
if (annotation.required() && value == null) {
throw new ValidationException(
String.format("%s不能为空: %s", field.getName(), annotation.message())
);
}
if (value != null) {
// 校验长度
if (value instanceof String) {
String strValue = (String) value;
// 校验最小长度
if (strValue.length() < annotation.minLength()) {
throw new ValidationException(
String.format("%s长度最小为%d: %s",
field.getName(), annotation.minLength(), annotation.message())
);
}
// 校验最大长度
if (strValue.length() > annotation.maxLength()) {
throw new ValidationException(
String.format("%s长度最大为%d: %s",
field.getName(), annotation.maxLength(), annotation.message())
);
}
// 正则校验
if (!annotation.pattern().isEmpty()) {
Pattern pattern = Pattern.compile(annotation.pattern());
if (!pattern.matcher(strValue).matches()) {
throw new ValidationException(
String.format("%s格式不正确: %s", field.getName(), annotation.message())
);
}
}
}
}
}
}
// 自定义校验异常
public static class ValidationException extends RuntimeException {
public ValidationException(String message) {
super(message);
}
}
}
缓存处理器
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class CacheProcessor {
// 简单的本地缓存
private static ConcurrentHashMap<String, CacheEntry> cache = new ConcurrentHashMap<>();
/**
* 缓存条目
*/
private static class CacheEntry {
Object value;
long expireTime;
public CacheEntry(Object value, long expireTime) {
this.value = value;
this.expireTime = expireTime;
}
public boolean isExpired() {
return System.currentTimeMillis() > expireTime;
}
}
/**
* 从缓存获取数据
*/
public static Object get(String key) {
CacheEntry entry = cache.get(key);
if (entry != null) {
if (!entry.isExpired()) {
return entry.value;
} else {
cache.remove(key);
}
}
return null;
}
/**
* 放入缓存
*/
public static void put(String key, Object value, int expireSeconds) {
long expireTime = System.currentTimeMillis() + expireSeconds * 1000;
cache.put(key, new CacheEntry(value, expireTime));
}
/**
* 清除缓存
*/
public static void clear() {
cache.clear();
}
/**
* 获取cache size
*/
public static int size() {
return cache.size();
}
}
使用示例
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class UserService {
/**
* 注册用户 - 使用日志注解
*/
@LogAnnotation(
action = "用户注册",
description = "注册新用户",
level = LogAnnotation.LogLevel.INFO
)
public Map<String, Object> registerUser(@Validate User user) throws Exception {
// 手动校验(也可以通过AOP自动校验)
ValidationProcessor.validate(user);
Map<String, Object> result = new HashMap<>();
result.put("success", true);
result.put("userId", System.currentTimeMillis());
result.put("username", user.getUsername());
return result;
}
/**
* 获取用户信息 - 使用缓存注解
*/
@Cacheable(key = "#userId", expire = 30)
public Map<String, Object> getUserById(Long userId) {
// 模拟查询数据库
Map<String, Object> user = new HashMap<>();
user.put("id", userId);
user.put("name", "用户" + userId);
user.put("email", "user" + userId + "@example.com");
return user;
}
/**
* 更新用户 - 使用日志注解
*/
@LogAnnotation(
action = "更新用户",
description = "更新用户信息",
level = LogAnnotation.LogLevel.WARN
)
public void updateUser(Long userId, String email) {
System.out.println("更新用户: " + userId + ", email: " + email);
// 实际更新逻辑
}
}
配合AOP自动校验
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class ValidationAspect {
/**
* 自动校验带有@Validate注解的参数
*/
@Around("execution(* *(.., @Validate (*), ..))")
public Object validateParams(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
// 校验所有包含Validate注解的参数
for (Object arg : args) {
if (arg != null) {
try {
ValidationProcessor.validate(arg);
} catch (ValidationProcessor.ValidationException e) {
throw new RuntimeException("参数校验失败: " + e.getMessage());
}
}
}
return joinPoint.proceed();
}
}
综合使用示例
import java.util.Map;
public class AnnotationExample {
public static void main(String[] args) throws Exception {
UserService userService = new UserService();
// 创建用户对象
User user = new User();
user.setUsername("test_user");
user.setEmail("test@example.com");
user.setPassword("123456");
// 注册用户
Map<String, Object> result = userService.registerUser(user);
System.out.println("注册结果: " + result);
// 获取用户(带缓存)
Map<String, Object> userInfo = userService.getUserById(1L);
System.out.println("用户信息: " + userInfo);
// 再次获取(命中缓存)
Map<String, Object> cachedUser = userService.getUserById(1L);
System.out.println("缓存用户信息: " + cachedUser);
// 更新用户
userService.updateUser(1L, "newemail@example.com");
}
}
实体类定义
public class User {
@Validate(required = true, minLength = 3, maxLength = 20,
message = "用户名长度必须在3-20个字符之间")
private String username;
@Validate(required = true, pattern = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
message = "邮箱格式不正确")
private String email;
@Validate(required = true, minLength = 6, maxLength = 20,
message = "密码长度必须在6-20个字符之间")
private String password;
// getter和setter
}
运行结果示例
========== 开始执行 ==========
操作类名: UserService
操作方法: registerUser
操作类型: 用户注册
操作描述: 注册新用户
方法参数: [User{username='test_user', email='test@example.com', password='123456'}]
执行结果: SUCCESS
返回结果: {success=true, userId=1234567890, username=test_user}
执行耗时: 12 ms
========== 结束执行 ==========
注册结果: {success=true, userId=1234567890, username=test_user}
用户信息: {id=1, name=用户1, email=user1@example.com}
缓存用户信息: {id=1, name=用户1, email=user1@example.com}
这个案例展示了自定义注解的完整实现:
- 注解定义:定义日志、校验、缓存三种注解
- 处理器实现:通过AOP实现日志记录和参数校验
- 实际应用:在业务类中应用注解
- 扩展能力:支持自定义属性、默认值、枚举类型等
这种设计模式可以大大提高代码的复用性和维护性,是实现AOP编程的重要方式。