Java运行时注解
运行时注解通过反射读取,是实现框架配置功能的核心技术。
注解保留策略
只有 @Retention(RetentionPolicy.RUNTIME) 的注解才能在运行时通过反射获取。
Java
@Retention(RetentionPolicy.RUNTIME) // 必须是RUNTIME
@Target(ElementType.TYPE)
public @interface Table {
String name() default "";
}
反射读取注解
类注解
Java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table {
String name();
}
@Table(name = "t_user")
public class User {}
// 反射获取
Class<User> clazz = User.class;
// 检查是否存在注解
boolean hasAnnotation = clazz.isAnnotationPresent(Table.class);
// 获取注解
Table table = clazz.getAnnotation(Table.class);
if (table != null) {
String tableName = table.name(); // "t_user"
}
方法注解
Java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface GetMapping {
String value();
}
public class UserController {
@GetMapping("/users")
public List<User> listUsers() { return null; }
}
// 反射获取
Class<?> clazz = UserController.class;
Method method = clazz.getMethod("listUsers");
GetMapping mapping = method.getAnnotation(GetMapping.class);
String path = mapping.value(); // "/users"
字段注解
Java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
String name() default "";
boolean nullable() default true;
}
public class User {
@Column(name = "user_name", nullable = false)
private String username;
}
// 反射获取
Class<?> clazz = User.class;
Field field = clazz.getDeclaredField("username");
Column column = field.getAnnotation(Column.class);
String columnName = column.name(); // "user_name"
boolean nullable = column.nullable(); // false
参数注解
Java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Param {
String value();
}
public void save(@Param("name") String name,
@Param("age") int age) {}
// 反射获取
Method method = clazz.getMethod("save", String.class, int.class);
Parameter[] params = method.getParameters();
for (Parameter param : params) {
Param p = param.getAnnotation(Param.class);
if (p != null) {
System.out.println(p.value()); // "name", "age"
}
}
注解API汇总
| 方法 | 作用 |
|---|---|
| isAnnotationPresent(Class) | 检查是否存在指定注解 |
| getAnnotation(Class) | 获取单个注解 |
| getAnnotations() | 获取所有注解 |
| getAnnotationsByType(Class) | 获取重复注解 |
| getDeclaredAnnotations() | 获取本类声明的注解 |
实战:简易ORM框架
定义注解
Java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table {
String name();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
String name() default "";
boolean primaryKey() default false;
}
实体类
Java
@Table(name = "t_user")
public class User {
@Column(name = "id", primaryKey = true)
private Long id;
@Column(name = "username")
private String username;
@Column(name = "email")
private String email;
}
ORM处理器
Java
public class OrmHelper {
public static String getTableName(Class<?> clazz) {
Table table = clazz.getAnnotation(Table.class);
return table != null ? table.name() : clazz.getSimpleName().toLowerCase();
}
public static Map<String, Object> getColumnValues(Object obj) throws Exception {
Map<String, Object> map = new LinkedHashMap<>();
Class<?> clazz = obj.getClass();
for (Field field : clazz.getDeclaredFields()) {
Column column = field.getAnnotation(Column.class);
if (column != null) {
field.setAccessible(true);
String columnName = column.name().isEmpty() ?
field.getName() : column.name();
map.put(columnName, field.get(obj));
}
}
return map;
}
public static String getPrimaryKey(Class<?> clazz) {
for (Field field : clazz.getDeclaredFields()) {
Column column = field.getAnnotation(Column.class);
if (column != null && column.primaryKey()) {
return column.name().isEmpty() ? field.getName() : column.name();
}
}
return null;
}
}
生成SQL
Java
User user = new User();
user.setId(1L);
user.setUsername("张三");
user.setEmail("zhang@example.com");
String table = OrmHelper.getTableName(User.class);
Map<String, Object> values = OrmHelper.getColumnValues(user);
String pk = OrmHelper.getPrimaryKey(User.class);
// 生成INSERT语句
StringBuilder sql = new StringBuilder("INSERT INTO " + table + " (");
sql.append(String.join(", ", values.keySet()));
sql.append(") VALUES (");
sql.append(values.values().stream()
.map(v -> "'" + v + "'")
.collect(Collectors.joining(", ")));
sql.append(")");
// INSERT INTO t_user (id, username, email) VALUES ('1', '张三', 'zhang@example.com')
注意事项
注解成员必须有默认值或使用时赋值,不能为 null
反射读取字段注解时需要 setAccessible(true) 访问私有字段
getAnnotations() 包含继承的注解,getDeclaredAnnotations() 只返回本类声明
@Inherited 只对类注解有效,方法和字段注解不会继承
要点总结
- 运行时注解必须使用 @Retention(RetentionPolicy.RUNTIME)
- 通过反射API:getAnnotation()、isAnnotationPresent() 读取注解
- 类、方法、字段、参数都支持注解反射
- 广泛应用于ORM、依赖注入、Web路由等框架场景
📝 发现内容有误?点击此处直接编辑