注解体系详解
一、知识概述
注解(Annotation)是Java 5引入的一种元数据机制,它为代码提供了一种结构化的标记方式。注解本身不直接影响代码的执行,但可以被编译器、工具或框架读取并据此生成代码、进行验证或实现特定功能。
注解的作用
- 编译时检查:如
@Override帮助编译器检查方法重写是否正确 - 代码生成:如 Lombok 自动生成 getter/setter
- 运行时处理:如 Spring 的依赖注入、事务管理
- 文档生成:如 Javadoc 使用注解生成文档
注解分类
| 类型 | 保留范围 | 用途 |
|---|---|---|
| 源码注解 | 仅源码,编译后丢弃 | 编译时检查、APT处理 |
| 编译注解 | 编译后保留在class文件 | 编译时处理、静态分析 |
| 运行时注解 | 运行时通过反射获取 | 框架运行时处理 |
二、知识点详细讲解
2.1 内置注解
Java 提供了一系列内置注解:
// === 编译相关 ===
// 标记方法重写父类方法
@Override
public String toString() {
return "Override example";
}
// 标记已过时,不建议使用
@Deprecated
public void oldMethod() {
// 旧方法,但仍保留兼容性
}
// 抑制编译器警告
@SuppressWarnings("unchecked")
public void suppressWarning() {
List list = new ArrayList(); // 原始类型警告被抑制
}
// 标记功能性接口(只有一个抽象方法)
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
}
// === Java 9+ 模块相关 ===
// 模块导出
// @Module(...)
// === Java 14+ 预览特性 ===
// 标记预览特性API
// @PreviewFeature
2.2 元注解
元注解是用于定义注解的注解:
/**
* 元注解示例
*/
@Retention(RetentionPolicy.RUNTIME) // 保留策略
@Target(ElementType.METHOD) // 使用目标
@Documented // 包含在javadoc中
@Inherited // 可被子类继承
public @interface MyAnnotation {
String value() default "";
int count() default 0;
}
@Retention - 保留策略
public enum RetentionPolicy {
SOURCE, // 源码级,编译后丢弃
CLASS, // class级,保留到class文件但运行时不可见(默认)
RUNTIME // 运行时级,可通过反射读取
}
@Target - 使用目标
public enum ElementType {
TYPE, // 类、接口、枚举
FIELD, // 字段
METHOD, // 方法
PARAMETER, // 参数
CONSTRUCTOR, // 构造器
LOCAL_VARIABLE, // 局部变量
ANNOTATION_TYPE, // 注解类型
PACKAGE, // 包
TYPE_PARAMETER, // 类型参数(Java 8)
TYPE_USE // 类型使用(Java 8)
}
使用示例
// 不同目标示例
@Target(ElementType.TYPE)
@interface ClassAnnotation {}
@Target(ElementType.FIELD)
@interface FieldAnnotation {}
@Target(ElementType.METHOD)
@interface MethodAnnotation {}
@Target(ElementType.PARAMETER)
@interface ParamAnnotation {}
@Target({ElementType.FIELD, ElementType.METHOD})
@interface FieldOrMethodAnnotation {}
// Java 8 类型注解
@Target(ElementType.TYPE_USE)
@interface TypeAnnotation {}
// 类型注解使用示例
public class TypeAnnotationDemo {
// 类型声明
TypeAnnotationDemo.@TypeAnnotation Inner inner;
// 泛型参数
List<@TypeAnnotation String> strings;
// 类型转换
String s = (@TypeAnnotation String) new Object();
// instanceof
boolean isString = new Object() instanceof @TypeAnnotation String;
class Inner {}
}
2.3 自定义注解
/**
* 自定义注解:数据库表映射
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table {
String name() default "";
String schema() default "";
}
/**
* 自定义注解:字段映射
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
String name() default "";
boolean nullable() default true;
int length() default 255;
String defaultValue() default "";
}
/**
* 自定义注解:主键
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Id {
boolean autoIncrement() default true;
}
/**
* 自定义注解:忽略字段
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Ignore {}
/**
* 自定义注解:方法日志
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
String value() default "";
LogLevel level() default LogLevel.INFO;
enum LogLevel {
DEBUG, INFO, WARN, ERROR
}
}
/**
* 自定义注解:重复注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Repeatable(Roles.class)
public @interface Role {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Roles {
Role[] value();
}
2.4 注解属性类型
注解属性只能是以下类型:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface AnnotationTypes {
// 基本类型
int intValue();
long longValue();
double doubleValue();
boolean booleanValue();
// String
String stringValue();
// Class
Class<?> classValue();
// 枚举
ElementType enumValue();
// 注解
Table annotationValue();
// 以上类型的一维数组
int[] intArray();
String[] stringArray();
Class<?>[] classArray();
// 默认值
String withDefault() default "default";
// value() 是特殊属性,使用时可以省略属性名
// @AnnotationTypes("test") 等同于 @AnnotationTypes(value = "test")
String value() default "";
}
2.5 注解处理器(APT)
注解处理器在编译时处理注解,生成代码:
/**
* 自定义注解:用于生成Builder
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface GenerateBuilder {}
// 注解处理器需要继承 AbstractProcessor(通常单独放在 processor 模块)
// 这里展示处理器的核心逻辑框架
/*
public class BuilderProcessor extends AbstractProcessor {
@Override
public Set<String> getSupportedAnnotationTypes() {
return Set.of(GenerateBuilder.class.getCanonicalName());
}
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(GenerateBuilder.class)) {
// 处理每个被注解的类
// 生成 Builder 类代码
generateBuilderClass((TypeElement) element);
}
return true;
}
private void generateBuilderClass(TypeElement element) {
String className = element.getSimpleName().toString();
String builderClassName = className + "Builder";
// 使用 JavaPoet 或类似库生成代码
// ...
}
}
*/
2.6 运行时注解处理
通过反射读取运行时注解:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 注解处理器:运行时处理
*/
public class AnnotationProcessor {
/**
* 解析类上的注解
*/
public static void parseClassAnnotation(Class<?> clazz) {
// 检查类是否有@Table注解
if (clazz.isAnnotationPresent(Table.class)) {
Table table = clazz.getAnnotation(Table.class);
String tableName = table.name().isEmpty() ?
clazz.getSimpleName().toLowerCase() : table.name();
System.out.println("表名: " + tableName);
}
}
/**
* 解析字段上的注解
*/
public static void parseFieldAnnotations(Class<?> clazz) {
for (Field field : clazz.getDeclaredFields()) {
System.out.println("字段: " + field.getName());
// 检查@Id注解
if (field.isAnnotationPresent(Id.class)) {
Id id = field.getAnnotation(Id.class);
System.out.println(" - 主键, 自增: " + id.autoIncrement());
}
// 检查@Column注解
if (field.isAnnotationPresent(Column.class)) {
Column column = field.getAnnotation(Column.class);
System.out.println(" - 列名: " +
(column.name().isEmpty() ? field.getName() : column.name()));
System.out.println(" - 可空: " + column.nullable());
System.out.println(" - 长度: " + column.length());
}
// 检查@Ignore注解
if (field.isAnnotationPresent(Ignore.class)) {
System.out.println(" - 忽略该字段");
}
}
}
/**
* 解析方法上的注解
*/
public static void parseMethodAnnotations(Class<?> clazz) {
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Log.class)) {
Log log = method.getAnnotation(Log.class);
System.out.println("方法: " + method.getName() +
", 日志级别: " + log.level() +
", 描述: " + log.value());
}
}
}
/**
* 解析重复注解
*/
public static void parseRepeatableAnnotation(Class<?> clazz) {
// 方式1:获取容器注解
if (clazz.isAnnotationPresent(Roles.class)) {
Roles roles = clazz.getAnnotation(Roles.class);
for (Role role : roles.value()) {
System.out.println("角色: " + role.value());
}
}
// 方式2:Java 8+ 直接获取重复注解
Role[] roles = clazz.getAnnotationsByType(Role.class);
for (Role role : roles) {
System.out.println("角色: " + role.value());
}
}
}
三、可运行Java代码示例
完整示例:ORM框架核心
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;
// === 注解定义 ===
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Entity {
String tableName() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface ID {
String columnName() default "";
boolean autoIncrement() default true;
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Column {
String name() default "";
String type() default "VARCHAR";
int length() default 255;
boolean nullable() default true;
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Transient {}
// === 实体类 ===
@Entity(tableName = "users")
class User {
@ID(columnName = "user_id")
private Long id;
@Column(name = "username", length = 50, nullable = false)
private String username;
@Column(name = "email", length = 100)
private String email;
@Transient
private String password; // 不映射到数据库
@Column(name = "created_at", type = "DATETIME")
private Date createdAt;
// 构造器、getter、setter
public User() {}
public User(String username, String email) {
this.username = username;
this.email = email;
this.createdAt = new Date();
}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public Date getCreatedAt() { return createdAt; }
public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; }
}
// === ORM核心处理 ===
class SimpleORM {
/**
* 根据实体类生成建表SQL
*/
public static String generateCreateTableSQL(Class<?> entityClass) {
StringBuilder sql = new StringBuilder("CREATE TABLE ");
// 表名
Entity entity = entityClass.getAnnotation(Entity.class);
String tableName = entity.tableName().isEmpty() ?
entityClass.getSimpleName().toLowerCase() : entity.tableName();
sql.append(tableName).append(" (\n");
// 字段
List<String> columns = new ArrayList<>();
for (Field field : entityClass.getDeclaredFields()) {
if (field.isAnnotationPresent(Transient.class)) continue;
String columnDef = generateColumnDefinition(field);
columns.add(" " + columnDef);
}
// 主键约束
String primaryKey = findPrimaryKey(entityClass);
if (primaryKey != null) {
columns.add(" PRIMARY KEY (" + primaryKey + ")");
}
sql.append(String.join(",\n", columns));
sql.append("\n)");
return sql.toString();
}
private static String generateColumnDefinition(Field field) {
StringBuilder def = new StringBuilder();
// 列名
String columnName;
if (field.isAnnotationPresent(ID.class)) {
columnName = field.getAnnotation(ID.class).columnName();
if (columnName.isEmpty()) columnName = field.getName();
} else if (field.isAnnotationPresent(Column.class)) {
columnName = field.getAnnotation(Column.class).name();
if (columnName.isEmpty()) columnName = field.getName();
} else {
columnName = field.getName();
}
def.append(columnName);
// 类型
String type = "VARCHAR";
int length = 255;
if (field.isAnnotationPresent(Column.class)) {
Column column = field.getAnnotation(Column.class);
type = column.type();
length = column.length();
}
// 根据Java类型映射SQL类型
Class<?> fieldType = field.getType();
if (fieldType == Long.class || fieldType == long.class) {
def.append(" BIGINT");
} else if (fieldType == Integer.class || fieldType == int.class) {
def.append(" INT");
} else if (fieldType == String.class) {
def.append(" ").append(type);
if (length > 0 && !"TEXT".equalsIgnoreCase(type)) {
def.append("(").append(length).append(")");
}
} else if (fieldType == Date.class) {
def.append(" DATETIME");
} else if (fieldType == Boolean.class || fieldType == boolean.class) {
def.append(" TINYINT(1)");
}
// 可空
if (field.isAnnotationPresent(Column.class)) {
if (!field.getAnnotation(Column.class).nullable()) {
def.append(" NOT NULL");
}
}
// 自增
if (field.isAnnotationPresent(ID.class)) {
if (field.getAnnotation(ID.class).autoIncrement()) {
def.append(" AUTO_INCREMENT");
}
}
return def.toString();
}
private static String findPrimaryKey(Class<?> entityClass) {
for (Field field : entityClass.getDeclaredFields()) {
if (field.isAnnotationPresent(ID.class)) {
ID id = field.getAnnotation(ID.class);
return id.columnName().isEmpty() ? field.getName() : id.columnName();
}
}
return null;
}
/**
* 生成INSERT语句
*/
public static String generateInsertSQL(Object entity) throws Exception {
Class<?> clazz = entity.getClass();
Entity entityAnnotation = clazz.getAnnotation(Entity.class);
String tableName = entityAnnotation.tableName().isEmpty() ?
clazz.getSimpleName().toLowerCase() : entityAnnotation.tableName();
List<String> columns = new ArrayList<>();
List<String> values = new ArrayList<>();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Transient.class)) continue;
field.setAccessible(true);
Object value = field.get(entity);
if (value == null) continue;
// 列名
String columnName;
if (field.isAnnotationPresent(ID.class)) {
columnName = field.getAnnotation(ID.class).columnName();
if (columnName.isEmpty()) columnName = field.getName();
} else if (field.isAnnotationPresent(Column.class)) {
columnName = field.getAnnotation(Column.class).name();
if (columnName.isEmpty()) columnName = field.getName();
} else {
columnName = field.getName();
}
columns.add(columnName);
// 值
if (value instanceof String || value instanceof Date) {
values.add("'" + value + "'");
} else {
values.add(value.toString());
}
}
return String.format("INSERT INTO %s (%s) VALUES (%s)",
tableName,
String.join(", ", columns),
String.join(", ", values));
}
/**
* 根据ID生成查询语句
*/
public static String generateSelectByIdSQL(Class<?> entityClass, Object id) {
Entity entity = entityClass.getAnnotation(Entity.class);
String tableName = entity.tableName().isEmpty() ?
entityClass.getSimpleName().toLowerCase() : entity.tableName();
String pkColumn = findPrimaryKey(entityClass);
return String.format("SELECT * FROM %s WHERE %s = %s",
tableName, pkColumn,
id instanceof String ? "'" + id + "'" : id);
}
}
// === 运行示例 ===
class ORMDemo {
public static void main(String[] args) throws Exception {
// 生成建表SQL
System.out.println("=== 建表SQL ===");
System.out.println(SimpleORM.generateCreateTableSQL(User.class));
// 生成插入SQL
System.out.println("\n=== 插入SQL ===");
User user = new User("zhangsan", "zhangsan@example.com");
System.out.println(SimpleORM.generateInsertSQL(user));
// 生成查询SQL
System.out.println("\n=== 查询SQL ===");
System.out.println(SimpleORM.generateSelectByIdSQL(User.class, 1L));
}
}
完整示例:方法权限控制
import java.lang.annotation.*;
import java.lang.reflect.*;
// === 注解定义 ===
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequireRole {
String[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequirePermission {
String value();
}
// === 用户角色枚举 ===
enum Role {
ADMIN, MANAGER, USER, GUEST
}
// === 服务类 ===
class UserService {
@RequireRole("ADMIN")
public void deleteUser(Long userId) {
System.out.println("删除用户: " + userId);
}
@RequireRole({"ADMIN", "MANAGER"})
public void updateUser(Long userId, String newName) {
System.out.println("更新用户: " + userId + ", 新名称: " + newName);
}
@RequirePermission("user:read")
public User getUser(Long userId) {
System.out.println("查询用户: " + userId);
return new User("test", "test@example.com");
}
public void listUsers() {
System.out.println("列出所有用户");
}
}
// === 权限检查器 ===
class SecurityInterceptor {
private Role currentRole = Role.USER;
private Set<String> currentPermissions = new HashSet<>();
public void setRole(Role role) {
this.currentRole = role;
}
public void addPermission(String permission) {
this.currentPermissions.add(permission);
}
/**
* 方法调用拦截
*/
public Object invoke(Object target, String methodName, Object... args) throws Exception {
Method method = findMethod(target.getClass(), methodName, args);
// 检查角色
if (method.isAnnotationPresent(RequireRole.class)) {
RequireRole requireRole = method.getAnnotation(RequireRole.class);
boolean hasRole = false;
for (String role : requireRole.value()) {
if (currentRole.name().equals(role)) {
hasRole = true;
break;
}
}
if (!hasRole) {
throw new SecurityException("权限不足: 需要角色 " +
Arrays.toString(requireRole.value()) + ", 当前角色: " + currentRole);
}
}
// 检查权限
if (method.isAnnotationPresent(RequirePermission.class)) {
RequirePermission requirePerm = method.getAnnotation(RequirePermission.class);
if (!currentPermissions.contains(requirePerm.value())) {
throw new SecurityException("权限不足: 需要 " + requirePerm.value());
}
}
// 执行方法
return method.invoke(target, args);
}
private Method findMethod(Class<?> clazz, String name, Object[] args) {
for (Method method : clazz.getDeclaredMethods()) {
if (method.getName().equals(name) &&
method.getParameterCount() == args.length) {
return method;
}
}
throw new IllegalArgumentException("方法不存在: " + name);
}
}
// === 运行示例 ===
class SecurityDemo {
public static void main(String[] args) throws Exception {
UserService userService = new UserService();
SecurityInterceptor interceptor = new SecurityInterceptor();
// 场景1:普通用户尝试删除
System.out.println("=== 场景1: USER角色尝试删除用户 ===");
interceptor.setRole(Role.USER);
try {
interceptor.invoke(userService, "deleteUser", 1L);
} catch (SecurityException e) {
System.out.println("异常: " + e.getMessage());
}
// 场景2:管理员删除用户
System.out.println("\n=== 场景2: ADMIN角色删除用户 ===");
interceptor.setRole(Role.ADMIN);
interceptor.invoke(userService, "deleteUser", 1L);
// 场景3:管理员更新用户
System.out.println("\n=== 场景3: ADMIN角色更新用户 ===");
interceptor.invoke(userService, "updateUser", 1L, "新名字");
// 场景4:经理更新用户
System.out.println("\n=== 场景4: MANAGER角色更新用户 ===");
interceptor.setRole(Role.MANAGER);
interceptor.invoke(userService, "updateUser", 1L, "新名字");
// 场景5:检查权限
System.out.println("\n=== 场景5: 检查权限 ===");
interceptor.setRole(Role.USER);
try {
interceptor.invoke(userService, "getUser", 1L);
} catch (SecurityException e) {
System.out.println("异常: " + e.getMessage());
}
interceptor.addPermission("user:read");
interceptor.invoke(userService, "getUser", 1L);
}
}
四、实战应用场景
场景1:参数校验注解
import java.lang.annotation.*;
import java.lang.reflect.*;
// === 校验注解 ===
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface NotNull {
String message() default "不能为空";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Size {
int min() default 0;
int max() default Integer.MAX_VALUE;
String message() default "长度不符合要求";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Pattern {
String regex();
String message() default "格式不正确";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Range {
long min() default Long.MIN_VALUE;
long max() default Long.MAX_VALUE;
String message() default "数值范围不正确";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Valid {}
// === 实体类 ===
@Valid
class RegisterRequest {
@NotNull(message = "用户名不能为空")
@Size(min = 3, max = 20, message = "用户名长度需在3-20之间")
private String username;
@NotNull(message = "密码不能为空")
@Size(min = 6, max = 30, message = "密码长度需在6-30之间")
private String password;
@Pattern(regex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$", message = "邮箱格式不正确")
private String email;
@Range(min = 18, max = 120, message = "年龄需在18-120之间")
private Integer age;
// getter/setter
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
}
// === 校验器 ===
class Validator {
public static List<String> validate(Object obj) {
List<String> errors = new ArrayList<>();
if (!obj.getClass().isAnnotationPresent(Valid.class)) {
return errors;
}
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
Object value;
try {
value = field.get(obj);
} catch (IllegalAccessException e) {
continue;
}
// @NotNull
if (field.isAnnotationPresent(NotNull.class)) {
if (value == null || (value instanceof String && ((String) value).isEmpty())) {
errors.add(field.getName() + ": " + field.getAnnotation(NotNull.class).message());
}
}
// @Size
if (field.isAnnotationPresent(Size.class) && value != null) {
Size size = field.getAnnotation(Size.class);
int length = value instanceof String ? ((String) value).length() : 0;
if (length < size.min() || length > size.max()) {
errors.add(field.getName() + ": " + size.message());
}
}
// @Pattern
if (field.isAnnotationPresent(Pattern.class) && value != null) {
Pattern pattern = field.getAnnotation(Pattern.class);
if (!java.util.regex.Pattern.matches(pattern.regex(), value.toString())) {
errors.add(field.getName() + ": " + pattern.message());
}
}
// @Range
if (field.isAnnotationPresent(Range.class) && value instanceof Number) {
Range range = field.getAnnotation(Range.class);
long numValue = ((Number) value).longValue();
if (numValue < range.min() || numValue > range.max()) {
errors.add(field.getName() + ": " + range.message());
}
}
}
return errors;
}
}
// === 运行示例 ===
class ValidationDemo {
public static void main(String[] args) {
RegisterRequest request = new RegisterRequest();
request.setUsername("ab"); // 太短
request.setPassword("123"); // 太短
request.setEmail("invalid-email"); // 格式错误
request.setAge(15); // 年龄太小
List<String> errors = Validator.validate(request);
if (errors.isEmpty()) {
System.out.println("校验通过");
} else {
System.out.println("校验失败:");
errors.forEach(System.out::println);
}
}
}
场景2:缓存注解
import java.lang.annotation.*;
import java.util.concurrent.*;
// === 缓存注解 ===
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Cacheable {
String key() default "";
int expire() default 300; // 秒
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface CacheEvict {
String key();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface CachePut {
String key();
}
// === 缓存管理器 ===
class CacheManager {
private static final ConcurrentHashMap<String, CacheEntry> cache = new ConcurrentHashMap<>();
static class CacheEntry {
Object value;
long expireTime;
CacheEntry(Object value, int expireSeconds) {
this.value = value;
this.expireTime = System.currentTimeMillis() + expireSeconds * 1000L;
}
boolean isExpired() {
return System.currentTimeMillis() > expireTime;
}
}
public static Object get(String key) {
CacheEntry entry = cache.get(key);
if (entry == null || entry.isExpired()) {
cache.remove(key);
return null;
}
return entry.value;
}
public static void put(String key, Object value, int expireSeconds) {
cache.put(key, new CacheEntry(value, expireSeconds));
}
public static void evict(String key) {
cache.remove(key);
}
}
// === 服务类 ===
class ProductService {
private int callCount = 0;
@Cacheable(key = "product:", expire = 60)
public String getProduct(String productId) {
callCount++;
System.out.println("执行getProduct方法,第" + callCount + "次");
return "Product-" + productId + "-" + System.currentTimeMillis();
}
@CacheEvict(key = "product:")
public void updateProduct(String productId, String newName) {
System.out.println("更新产品: " + productId);
}
@CachePut(key = "product:")
public String saveProduct(String productId, String name) {
System.out.println("保存产品: " + productId);
return name;
}
}
// === 缓存代理 ===
class CacheProxy {
public static Object invoke(Object target, Method method, Object... args) throws Exception {
// 处理 @Cacheable
if (method.isAnnotationPresent(Cacheable.class)) {
Cacheable cacheable = method.getAnnotation(Cacheable.class);
String key = cacheable.key() + (args.length > 0 ? args[0].toString() : "");
Object cached = CacheManager.get(key);
if (cached != null) {
System.out.println("缓存命中: " + key);
return cached;
}
System.out.println("缓存未命中: " + key);
Object result = method.invoke(target, args);
CacheManager.put(key, result, cacheable.expire());
return result;
}
// 处理 @CacheEvict
if (method.isAnnotationPresent(CacheEvict.class)) {
CacheEvict evict = method.getAnnotation(CacheEvict.class);
String key = evict.key() + (args.length > 0 ? args[0].toString() : "");
CacheManager.evict(key);
System.out.println("清除缓存: " + key);
return method.invoke(target, args);
}
// 处理 @CachePut
if (method.isAnnotationPresent(CachePut.class)) {
CachePut put = method.getAnnotation(CachePut.class);
Object result = method.invoke(target, args);
String key = put.key() + (args.length > 0 ? args[0].toString() : "");
CacheManager.put(key, result, 300);
System.out.println("更新缓存: " + key);
return result;
}
return method.invoke(target, args);
}
}
// === 运行示例 ===
class CacheDemo {
public static void main(String[] args) throws Exception {
ProductService service = new ProductService();
Method getProduct = ProductService.class.getMethod("getProduct", String.class);
Method updateProduct = ProductService.class.getMethod("updateProduct", String.class, String.class);
// 第一次调用,缓存未命中
System.out.println("=== 第一次调用 ===");
String result1 = (String) CacheProxy.invoke(service, getProduct, "P001");
System.out.println("结果: " + result1);
// 第二次调用,缓存命中
System.out.println("\n=== 第二次调用 ===");
String result2 = (String) CacheProxy.invoke(service, getProduct, "P001");
System.out.println("结果: " + result2);
// 更新产品,清除缓存
System.out.println("\n=== 更新产品 ===");
CacheProxy.invoke(service, updateProduct, "P001", "New Product");
// 再次调用,缓存重新加载
System.out.println("\n=== 更新后调用 ===");
String result3 = (String) CacheProxy.invoke(service, getProduct, "P001");
System.out.println("结果: " + result3);
}
}
五、总结与最佳实践
核心要点回顾
| 概念 | 说明 |
|---|---|
| 内置注解 | @Override、@Deprecated、@SuppressWarnings等 |
| 元注解 | 定义注解的注解:@Retention、@Target、@Documented、@Inherited |
| 自定义注解 | 使用 @interface 关键字定义 |
| 注解属性 | 只能是基本类型、String、Class、枚举、注解及其数组 |
| 保留策略 | SOURCE、CLASS、RUNTIME |
| 注解处理 | APT(编译时)、反射(运行时) |
最佳实践
-
选择合适的保留策略
- 编译时检查用
SOURCE - 运行时处理用
RUNTIME - 生成文档用
RUNTIME+@Documented
- 编译时检查用
-
合理设置目标
@Target(ElementType.METHOD) // 方法级注解 @Target({ElementType.TYPE, ElementType.METHOD}) // 类或方法 -
使用默认值提高易用性
public @interface MyAnnotation { String value() default ""; boolean enabled() default true; } -
善用 @Repeatable
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Repeatable(Roles.class) public @interface Role { String value(); } -
结合反射实现框架功能
- 依赖注入
- AOP拦截
- ORM映射
- 参数校验
-
注意性能
- 反射读取注解有一定开销
- 高频场景考虑缓存注解信息
常见框架注解
| 框架 | 常用注解 |
|---|---|
| Spring | @Component、@Autowired、@Transactional、@RequestMapping |
| Spring Boot | @SpringBootApplication、@ConfigurationProperties |
| MyBatis | @Select、@Insert、@Update、@Delete |
| JPA | @Entity、@Table、@Column、@Id |
| Lombok | @Data、@Getter、@Setter、@Builder |
| Validation | @NotNull、@Size、@Pattern、@Email |
扩展阅读
- Java 语言规范:注解的正式定义
- Annotation Processing Tool (APT):编译时代码生成
- Lombok 原理:如何通过注解生成代码
- Spring 注解驱动开发:@Autowired、@Transactional 的实现原理