Java注解深度剖析与实战应用
目录
- 一、注解概述
- 二、Java内置注解
- 三、元注解详解
- 四、自定义注解
- 五、注解处理器
- 六、Spring框架中的注解
- 七、MyBatis注解应用
- 八、参数校验注解(JSR-303)
- 九、注解实战:自定义权限校验
- 十、注解最佳实践
- 总结
一、注解概述
1.1 什么是注解
Java注解(Annotation)是JDK 5.0引入的一种特殊标记,可以附加在包、类、方法、字段等程序元素上。注解不会直接影响代码的执行,但可以被编译器、工具或运行时环境读取和处理。
+-------------------+
| 源代码层面 | @Override, @Deprecated
+-------------------+
↓
+-------------------+
| 编译期处理 | Lombok, APT
+-------------------+
↓
+-------------------+
| 运行期处理 | Spring, MyBatis
+-------------------+
1.2 注解的作用
| 作用类型 | 说明 | 示例 |
|---|---|---|
| 编译检查 | 让编译器进行语法检查 | @Override、@SuppressWarnings |
| 代码分析 | 通过注解进行代码分析 | @Deprecated、@FunctionalInterface |
| 生成文档 | 生成JavaDoc文档 | @param、@return |
| 代码生成 | 自动生成代码 | Lombok的@Data、@Builder |
| 运行时处理 | 运行时通过反射获取注解信息 | Spring的@Autowired、@Transactional |
1.3 注解 vs 注释
// 这是注释 - 给人看的,编译后会被删除
/**
* JavaDoc注释 - 可以生成文档
*/
// 这是注解 - 给程序看的,可以保留到运行时
@Override
public String toString() {
return "Annotation Example";
}
二、Java内置注解
2.1 基本内置注解
package com.example.annotation;
/**
* Java内置注解示例
*/
public class BuiltInAnnotationDemo {
/**
* @Override - 表示方法重写父类方法
* 作用: 编译器会检查是否真的重写了父类方法
*/
@Override
public String toString() {
return "BuiltInAnnotationDemo";
}
/**
* @Deprecated - 表示已过时
* 作用: 编译器会给出警告,提示不建议使用
*/
@Deprecated
public void oldMethod() {
System.out.println("这是一个过时的方法");
}
/**
* @SuppressWarnings - 抑制编译警告
* 常用参数:
* - "unchecked": 抑制未检查的转换警告
* - "deprecation": 抑制使用废弃API的警告
* - "rawtypes": 抑制原始类型警告
* - "all": 抑制所有警告
*/
@SuppressWarnings("deprecation")
public void callOldMethod() {
oldMethod(); // 不会有警告
}
@SuppressWarnings({"unchecked", "rawtypes"})
public void useRawType() {
java.util.List list = new java.util.ArrayList();
list.add("item"); // 不会有警告
}
/**
* @FunctionalInterface - 标记函数式接口
* 作用: 确保接口只有一个抽象方法
*/
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
// 可以有default方法
default void print() {
System.out.println("Calculator");
}
}
/**
* @SafeVarargs - 抑制可变参数泛型警告
*/
@SafeVarargs
public final <T> void printAll(T... items) {
for (T item : items) {
System.out.println(item);
}
}
public static void main(String[] args) {
BuiltInAnnotationDemo demo = new BuiltInAnnotationDemo();
// 使用函数式接口
Calculator add = (a, b) -> a + b;
System.out.println("5 + 3 = " + add.calculate(5, 3));
// 使用可变参数方法
demo.printAll("A", "B", "C");
}
}
2.2 JDK 9+ 新增注解
package com.example.annotation;
/**
* JDK 9+ 新增注解示例
*/
public class NewAnnotationDemo {
/**
* @since 9 - Java 9新增
* 用于标记已废弃的API,并提供更详细的信息
*/
@Deprecated(since = "9", forRemoval = true)
public void willBeRemoved() {
System.out.println("此方法将在未来版本中移除");
}
/**
* 使用被标记为移除的方法会收到更严重的警告
*/
public void useDeprecatedMethod() {
willBeRemoved(); // 会有警告: 此方法计划被移除
}
}
三、元注解详解
元注解(Meta-Annotation)是用来定义其他注解的注解,位于java.lang.annotation包中。
3.1 @Retention - 保留策略
package com.example.annotation.meta;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @Retention - 定义注解的生命周期
*
* 三种保留策略:
* +-----------------+------------------+-------------------+
* | RetentionPolicy | 保留阶段 | 典型应用 |
* +-----------------+------------------+-------------------+
* | SOURCE | 源码阶段 | @Override |
* | CLASS | 字节码阶段(默认) | APT处理器 |
* | RUNTIME | 运行时 | Spring, MyBatis |
* +-----------------+------------------+-------------------+
*/
// SOURCE - 只在源码中保留,编译后丢弃
@Retention(RetentionPolicy.SOURCE)
@interface SourceAnnotation {
String value();
}
// CLASS - 保留到字节码,运行时不可见(默认)
@Retention(RetentionPolicy.CLASS)
@interface ClassAnnotation {
String value();
}
// RUNTIME - 运行时可见,可通过反射读取
@Retention(RetentionPolicy.RUNTIME)
@interface RuntimeAnnotation {
String value();
}
/**
* 演示不同保留策略
*/
@SourceAnnotation("源码注解")
@ClassAnnotation("字节码注解")
@RuntimeAnnotation("运行时注解")
public class RetentionDemo {
public static void main(String[] args) {
Class<RetentionDemo> clazz = RetentionDemo.class;
System.out.println("=== 通过反射读取注解 ===");
// SOURCE注解: 读不到(已在编译时丢弃)
SourceAnnotation source = clazz.getAnnotation(SourceAnnotation.class);
System.out.println("SOURCE注解: " + source);
// CLASS注解: 读不到(运行时不可见)
ClassAnnotation classAnn = clazz.getAnnotation(ClassAnnotation.class);
System.out.println("CLASS注解: " + classAnn);
// RUNTIME注解: 能读到
RuntimeAnnotation runtime = clazz.getAnnotation(RuntimeAnnotation.class);
System.out.println("RUNTIME注解: " + runtime);
if (runtime != null) {
System.out.println(" value = " + runtime.value());
}
}
}
3.2 @Target - 作用目标
package com.example.annotation.meta;
import java.lang.annotation.*;
/**
* @Target - 定义注解可以用在哪些地方
*/
// 只能用在类上
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Entity {
String tableName();
}
// 只能用在字段上
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Column {
String name();
boolean nullable() default true;
}
// 只能用在方法上
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Transactional {
String value() default "";
}
// 可以用在多个地方
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface Validate {
String pattern();
}
/**
* ElementType枚举值说明:
* +------------------+------------------------+
* | ElementType | 说明 |
* +------------------+------------------------+
* | TYPE | 类、接口、枚举 |
* | FIELD | 字段 |
* | METHOD | 方法 |
* | PARAMETER | 方法参数 |
* | CONSTRUCTOR | 构造器 |
* | LOCAL_VARIABLE | 局部变量 |
* | ANNOTATION_TYPE | 注解类型 |
* | PACKAGE | 包 |
* | TYPE_PARAMETER | 类型参数(泛型) |
* | TYPE_USE | 任何类型使用的地方 |
* +------------------+------------------------+
*/
@Entity(tableName = "user")
public class TargetDemo {
@Column(name = "user_id")
@Validate(pattern = "\\d+")
private Long id;
@Column(name = "username", nullable = false)
@Validate(pattern = "[a-zA-Z0-9_]+")
private String username;
@Transactional
@Validate(pattern = ".*")
public void save() {
System.out.println("保存数据");
}
}
3.3 @Documented - 生成文档
package com.example.annotation.meta;
import java.lang.annotation.*;
/**
* @Documented - 将注解包含在JavaDoc中
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface ApiDoc {
String description();
String version() default "1.0";
}
public class DocumentedDemo {
/**
* 用户登录接口
* 此方法的注解会出现在JavaDoc中
*/
@ApiDoc(description = "用户登录", version = "2.0")
public void login(String username, String password) {
System.out.println("登录: " + username);
}
}
3.4 @Inherited - 注解继承
package com.example.annotation.meta;
import java.lang.annotation.*;
/**
* @Inherited - 允许子类继承父类的注解
* 注意: 只对类有效,对方法/字段无效
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface ParentAnnotation {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface NoInheritedAnnotation {
String value();
}
@ParentAnnotation("父类注解")
@NoInheritedAnnotation("不继承的注解")
class Parent {
}
// 子类会继承@ParentAnnotation,但不会继承@NoInheritedAnnotation
class Child extends Parent {
}
public class InheritedDemo {
public static void main(String[] args) {
Class<Child> clazz = Child.class;
ParentAnnotation parent = clazz.getAnnotation(ParentAnnotation.class);
System.out.println("@ParentAnnotation: " +
(parent != null ? parent.value() : "null"));
NoInheritedAnnotation noInherited = clazz.getAnnotation(NoInheritedAnnotation.class);
System.out.println("@NoInheritedAnnotation: " +
(noInherited != null ? noInherited.value() : "null"));
}
}
3.5 @Repeatable - 重复注解
package com.example.annotation.meta;
import java.lang.annotation.*;
/**
* @Repeatable - 允许在同一位置多次使用同一注解(Java 8+)
*/
@Repeatable(Schedules.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Schedule {
String day();
String time();
}
// 容器注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Schedules {
Schedule[] value();
}
public class RepeatableDemo {
// Java 8之前需要这样写:
// @Schedules({
// @Schedule(day = "Monday", time = "09:00"),
// @Schedule(day = "Friday", time = "14:00")
// })
// Java 8+可以直接重复使用:
@Schedule(day = "Monday", time = "09:00")
@Schedule(day = "Wednesday", time = "10:00")
@Schedule(day = "Friday", time = "14:00")
public void meeting() {
System.out.println("开会");
}
public static void main(String[] args) throws Exception {
var method = RepeatableDemo.class.getMethod("meeting");
// 获取所有Schedule注解
Schedule[] schedules = method.getAnnotationsByType(Schedule.class);
System.out.println("=== 会议时间表 ===");
for (Schedule schedule : schedules) {
System.out.println(schedule.day() + " " + schedule.time());
}
}
}
四、自定义注解
4.1 自定义注解语法
package com.example.annotation.custom;
import java.lang.annotation.*;
/**
* 自定义注解语法结构
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CustomAnnotation {
// 1. 基本属性(无默认值,使用时必须指定)
String name();
// 2. 带默认值的属性
int age() default 0;
// 3. 数组类型属性
String[] tags() default {};
// 4. 枚举类型属性
Priority priority() default Priority.MEDIUM;
// 5. Class类型属性
Class<?> type() default Void.class;
// 6. 其他注解类型
Description description() default @Description(value = "默认描述");
// 7. value属性(特殊名称,使用时可省略"value=")
String value() default "";
}
enum Priority {
LOW, MEDIUM, HIGH
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Description {
String value();
}
/**
* 使用自定义注解
*/
// 完整写法
@CustomAnnotation(
name = "测试类",
age = 10,
tags = {"test", "demo"},
priority = Priority.HIGH,
type = String.class,
description = @Description("这是一个测试类"),
value = "简化写法"
)
class FullDemo {
}
// 简化写法(只有value时)
@CustomAnnotation("简化写法")
class SimpleDemo {
}
4.2 实战案例:Excel导出注解
package com.example.annotation.custom;
import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* Excel导出注解(类似EasyExcel)
*/
// 标记在类上,指定Sheet名称
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface ExcelSheet {
String name() default "Sheet1";
}
// 标记在字段上,指定列名和顺序
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface ExcelColumn {
String name(); // 列名
int order() default 0; // 列顺序
String format() default ""; // 格式化(日期等)
boolean ignore() default false; // 是否忽略
}
/**
* 用户实体
*/
@ExcelSheet(name = "用户列表")
class User {
@ExcelColumn(name = "用户ID", order = 1)
private Long id;
@ExcelColumn(name = "用户名", order = 2)
private String username;
@ExcelColumn(name = "邮箱", order = 3)
private String email;
@ExcelColumn(name = "年龄", order = 4)
private Integer age;
@ExcelColumn(name = "创建时间", order = 5, format = "yyyy-MM-dd HH:mm:ss")
private java.util.Date createTime;
@ExcelColumn(name = "密码", ignore = true) // 敏感信息不导出
private String password;
public User(Long id, String username, String email, Integer age, String password) {
this.id = id;
this.username = username;
this.email = email;
this.age = age;
this.password = password;
this.createTime = new java.util.Date();
}
// Getters
public Long getId() { return id; }
public String getUsername() { return username; }
public String getEmail() { return email; }
public Integer getAge() { return age; }
public java.util.Date getCreateTime() { return createTime; }
public String getPassword() { return password; }
}
/**
* Excel导出工具类
*/
class ExcelExporter {
/**
* 导出数据(简化版,实际应使用POI库)
*/
public static <T> void export(List<T> dataList) throws Exception {
if (dataList == null || dataList.isEmpty()) {
System.out.println("数据为空");
return;
}
Class<?> clazz = dataList.get(0).getClass();
// 1. 获取Sheet名称
String sheetName = "Sheet1";
if (clazz.isAnnotationPresent(ExcelSheet.class)) {
ExcelSheet sheet = clazz.getAnnotation(ExcelSheet.class);
sheetName = sheet.name();
}
System.out.println("=== 导出Excel: " + sheetName + " ===\n");
// 2. 获取所有需要导出的字段
List<FieldInfo> fieldInfos = new ArrayList<>();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(ExcelColumn.class)) {
ExcelColumn column = field.getAnnotation(ExcelColumn.class);
if (!column.ignore()) {
fieldInfos.add(new FieldInfo(field, column));
}
}
}
// 3. 按order排序
fieldInfos.sort((a, b) -> a.column.order() - b.column.order());
// 4. 打印表头
for (FieldInfo info : fieldInfos) {
System.out.print(info.column.name() + "\t");
}
System.out.println();
System.out.println("-----------------------------------------------------------");
// 5. 打印数据
for (T data : dataList) {
for (FieldInfo info : fieldInfos) {
info.field.setAccessible(true);
Object value = info.field.get(data);
// 格式化处理
if (value instanceof java.util.Date && !info.column.format().isEmpty()) {
value = new java.text.SimpleDateFormat(info.column.format()).format(value);
}
System.out.print(value + "\t");
}
System.out.println();
}
}
static class FieldInfo {
Field field;
ExcelColumn column;
FieldInfo(Field field, ExcelColumn column) {
this.field = field;
this.column = column;
}
}
}
/**
* 测试Excel导出
*/
class ExcelExportDemo {
public static void main(String[] args) throws Exception {
List<User> users = new ArrayList<>();
users.add(new User(1L, "zhangsan", "zhangsan@example.com", 25, "pass123"));
users.add(new User(2L, "lisi", "lisi@example.com", 30, "pass456"));
users.add(new User(3L, "wangwu", "wangwu@example.com", 28, "pass789"));
// 导出Excel
ExcelExporter.export(users);
}
}
五、注解处理器
5.1 运行时注解处理器
package com.example.annotation.processor;
import java.lang.annotation.*;
import java.lang.reflect.Method;
/**
* 运行时注解处理器 - 通过反射读取注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface PerformanceTest {
int iterations() default 1;
}
/**
* 性能测试工具
*/
class PerformanceTester {
/**
* 执行所有带@PerformanceTest注解的方法
*/
public static void runTests(Object obj) throws Exception {
Class<?> clazz = obj.getClass();
Method[] methods = clazz.getDeclaredMethods();
System.out.println("=== 性能测试报告 ===\n");
for (Method method : methods) {
if (method.isAnnotationPresent(PerformanceTest.class)) {
PerformanceTest test = method.getAnnotation(PerformanceTest.class);
// 执行测试
method.setAccessible(true);
long startTime = System.nanoTime();
for (int i = 0; i < test.iterations(); i++) {
method.invoke(obj);
}
long endTime = System.nanoTime();
double avgTime = (endTime - startTime) / 1_000_000.0 / test.iterations();
System.out.println("方法: " + method.getName());
System.out.println("迭代次数: " + test.iterations());
System.out.println("平均耗时: " + String.format("%.3f", avgTime) + "ms");
System.out.println("---");
}
}
}
}
/**
* 测试类
*/
class MyService {
@PerformanceTest(iterations = 1000)
public void quickMethod() {
// 快速方法
int sum = 0;
for (int i = 0; i < 100; i++) {
sum += i;
}
}
@PerformanceTest(iterations = 100)
public void slowMethod() {
// 慢方法
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void normalMethod() {
// 没有注解,不会被测试
System.out.println("普通方法");
}
}
/**
* 运行测试
*/
class RuntimeProcessorDemo {
public static void main(String[] args) throws Exception {
MyService service = new MyService();
PerformanceTester.runTests(service);
}
}
5.2 编译期注解处理器(APT)
package com.example.annotation.processor;
/**
* 编译期注解处理器 - APT(Annotation Processing Tool)
*
* 典型应用:
* 1. Lombok: @Data, @Builder等自动生成代码
* 2. Dagger: 依赖注入框架
* 3. ButterKnife: Android视图绑定
* 4. MapStruct: 对象映射工具
*
* APT处理流程:
* +------------------+
* | 源代码(.java) |
* +------------------+
* ↓
* +------------------+
* | 注解处理器(APT) | <-- 读取注解,生成新代码
* +------------------+
* ↓
* +------------------+
* | 生成代码(.java) |
* +------------------+
* ↓
* +------------------+
* | 编译成字节码 |
* +------------------+
*/
/**
* Lombok @Data注解原理演示
*
* 使用@Data前:
* @Data
* public class User {
* private Long id;
* private String name;
* }
*
* APT生成后的代码:
* public class User {
* private Long id;
* private String name;
*
* public Long getId() { return id; }
* public void setId(Long id) { this.id = id; }
* public String getName() { return name; }
* public void setName(String name) { this.name = name; }
*
* @Override
* public boolean equals(Object o) { ... }
* @Override
* public int hashCode() { ... }
* @Override
* public String toString() { ... }
* }
*/
public class AptDemo {
public static void main(String[] args) {
System.out.println("=== 编译期注解处理器(APT) ===\n");
System.out.println("APT的优势:");
System.out.println("1. 编译期生成代码,运行时零成本");
System.out.println("2. 减少样板代码,提高开发效率");
System.out.println("3. 类型安全,编译期检查");
System.out.println("4. 性能优于反射");
System.out.println("\n常见APT框架:");
System.out.println("• Lombok - 自动生成getter/setter/toString等");
System.out.println("• MapStruct - Bean映射");
System.out.println("• Dagger/Hilt - 依赖注入");
System.out.println("• ButterKnife - 视图绑定");
System.out.println("• AutoService - SPI自动注册");
}
}
六、Spring框架中的注解
6.1 Spring核心注解
package com.example.annotation.spring;
import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* 模拟Spring核心注解
*/
// === 组件注解 ===
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Component {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Service {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Repository {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Controller {
String value() default "";
}
// === 依赖注入注解 ===
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})
@interface Autowired {
boolean required() default true;
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@interface Qualifier {
String value();
}
// === 配置注解 ===
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Configuration {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Bean {
String name() default "";
}
// === 切面注解 ===
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Transactional {
String value() default "";
boolean readOnly() default false;
}
/**
* 简化版Spring容器
*/
class MiniSpringContainer {
private Map<Class<?>, Object> beans = new HashMap<>();
/**
* 扫描并注册Bean
*/
public void scan(Class<?>... classes) throws Exception {
for (Class<?> clazz : classes) {
if (clazz.isAnnotationPresent(Component.class) ||
clazz.isAnnotationPresent(Service.class) ||
clazz.isAnnotationPresent(Repository.class) ||
clazz.isAnnotationPresent(Controller.class)) {
// 创建实例
Object instance = clazz.getDeclaredConstructor().newInstance();
beans.put(clazz, instance);
System.out.println("注册Bean: " + clazz.getSimpleName());
}
}
// 处理依赖注入
for (Object bean : beans.values()) {
injectDependencies(bean);
}
}
/**
* 依赖注入
*/
private void injectDependencies(Object bean) throws Exception {
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
field.setAccessible(true);
Object dependency = beans.get(field.getType());
if (dependency != null) {
field.set(bean, dependency);
System.out.println(" 注入: " + bean.getClass().getSimpleName() +
"." + field.getName());
}
}
}
}
/**
* 获取Bean
*/
@SuppressWarnings("unchecked")
public <T> T getBean(Class<T> clazz) {
return (T) beans.get(clazz);
}
/**
* 执行带@Transactional的方法(AOP)
*/
public Object executeWithTransaction(Object bean, String methodName) throws Exception {
Method method = bean.getClass().getDeclaredMethod(methodName);
if (method.isAnnotationPresent(Transactional.class)) {
Transactional tx = method.getAnnotation(Transactional.class);
System.out.println("\n[事务开始] readOnly=" + tx.readOnly());
}
Object result = method.invoke(bean);
if (method.isAnnotationPresent(Transactional.class)) {
System.out.println("[事务提交]\n");
}
return result;
}
}
/**
* 业务层示例
*/
@Repository
class UserRepository {
public void save(String username) {
System.out.println(" [DAO] 保存用户: " + username);
}
}
@Service
class UserService {
@Autowired
private UserRepository userRepository;
@Transactional(readOnly = false)
public void registerUser(String username) {
System.out.println(" [Service] 执行注册逻辑");
userRepository.save(username);
}
@Transactional(readOnly = true)
public void queryUser(String username) {
System.out.println(" [Service] 查询用户: " + username);
}
}
@Controller
class UserController {
@Autowired
private UserService userService;
public void handleRegister(String username) {
System.out.println("[Controller] 接收注册请求");
userService.registerUser(username);
}
}
/**
* 测试Spring注解
*/
class SpringAnnotationDemo {
public static void main(String[] args) throws Exception {
// 创建容器并扫描
MiniSpringContainer container = new MiniSpringContainer();
container.scan(UserRepository.class, UserService.class, UserController.class);
System.out.println("\n=== 测试依赖注入和事务 ===\n");
// 获取Controller并调用
UserController controller = container.getBean(UserController.class);
controller.handleRegister("zhangsan");
// 测试事务注解
UserService service = container.getBean(UserService.class);
container.executeWithTransaction(service, "queryUser");
}
}
6.2 Spring MVC注解
package com.example.annotation.spring;
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
/**
* Spring MVC核心注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface RestController {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@interface RequestMapping {
String value() default "";
String method() default "GET";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface GetMapping {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface PostMapping {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@interface RequestParam {
String value();
boolean required() default true;
String defaultValue() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@interface PathVariable {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@interface RequestBody {
}
/**
* REST API Controller
*/
@RestController
@RequestMapping("/api/users")
class UserRestController {
@GetMapping("/list")
public String listUsers(@RequestParam(value = "page", defaultValue = "1") int page,
@RequestParam(value = "size", defaultValue = "10") int size) {
return "用户列表: page=" + page + ", size=" + size;
}
@GetMapping("/{id}")
public String getUser(@PathVariable("id") Long id) {
return "获取用户: id=" + id;
}
@PostMapping("/create")
public String createUser(@RequestBody String userData) {
return "创建用户: " + userData;
}
}
/**
* 简化版MVC请求分发器
*/
class SimpleDispatcherServlet {
/**
* 模拟处理HTTP请求
*/
public static String handleRequest(Object controller, String uri, String method,
Map<String, String> params) throws Exception {
Class<?> clazz = controller.getClass();
// 获取Controller路径
String basePath = "";
if (clazz.isAnnotationPresent(RequestMapping.class)) {
basePath = clazz.getAnnotation(RequestMapping.class).value();
}
// 查找匹配的方法
for (Method m : clazz.getDeclaredMethods()) {
String methodPath = getMethodPath(m);
if (methodPath == null) continue;
String fullPath = basePath + methodPath;
// 简化的路径匹配
if (matchPath(uri, fullPath)) {
System.out.println("\n[DispatcherServlet] " + method + " " + uri);
System.out.println("[DispatcherServlet] 匹配到方法: " + m.getName());
// 准备参数
Object[] args = prepareArguments(m, uri, params);
// 调用方法
return (String) m.invoke(controller, args);
}
}
return "404 Not Found";
}
private static String getMethodPath(Method method) {
if (method.isAnnotationPresent(GetMapping.class)) {
return method.getAnnotation(GetMapping.class).value();
}
if (method.isAnnotationPresent(PostMapping.class)) {
return method.getAnnotation(PostMapping.class).value();
}
return null;
}
private static boolean matchPath(String uri, String pattern) {
// 简化的路径匹配
if (pattern.contains("{")) {
String regex = pattern.replaceAll("\\{[^}]+\\}", "[^/]+");
return uri.matches(regex);
}
return uri.equals(pattern);
}
private static Object[] prepareArguments(Method method, String uri,
Map<String, String> params) {
Parameter[] parameters = method.getParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
Parameter param = parameters[i];
if (param.isAnnotationPresent(RequestParam.class)) {
RequestParam rp = param.getAnnotation(RequestParam.class);
String value = params.getOrDefault(rp.value(), rp.defaultValue());
args[i] = convertType(value, param.getType());
} else if (param.isAnnotationPresent(PathVariable.class)) {
PathVariable pv = param.getAnnotation(PathVariable.class);
// 简化:从URI中提取值
args[i] = 1L;
} else if (param.isAnnotationPresent(RequestBody.class)) {
args[i] = "{\"username\":\"zhangsan\"}";
}
}
return args;
}
private static Object convertType(String value, Class<?> type) {
if (type == int.class || type == Integer.class) {
return Integer.parseInt(value);
}
return value;
}
}
/**
* 测试Spring MVC注解
*/
class SpringMvcDemo {
public static void main(String[] args) throws Exception {
UserRestController controller = new UserRestController();
// 测试GET请求
Map<String, String> params1 = new HashMap<>();
params1.put("page", "2");
params1.put("size", "20");
String result1 = SimpleDispatcherServlet.handleRequest(
controller, "/api/users/list", "GET", params1);
System.out.println("响应: " + result1);
// 测试路径变量
String result2 = SimpleDispatcherServlet.handleRequest(
controller, "/api/users/123", "GET", new HashMap<>());
System.out.println("响应: " + result2);
// 测试POST请求
String result3 = SimpleDispatcherServlet.handleRequest(
controller, "/api/users/create", "POST", new HashMap<>());
System.out.println("响应: " + result3);
}
}
七、MyBatis注解应用
package com.example.annotation.mybatis;
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;
/**
* MyBatis注解式开发
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Select {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Insert {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Update {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Delete {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@interface Param {
String value();
}
/**
* Mapper接口
*/
interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User findById(@Param("id") Long id);
@Select("SELECT * FROM user WHERE username = #{username}")
User findByUsername(@Param("username") String username);
@Insert("INSERT INTO user(id, username, email) VALUES(#{id}, #{username}, #{email})")
int insert(@Param("user") User user);
@Update("UPDATE user SET email = #{email} WHERE id = #{id}")
int updateEmail(@Param("id") Long id, @Param("email") String email);
@Delete("DELETE FROM user WHERE id = #{id}")
int deleteById(@Param("id") Long id);
}
/**
* 实体类
*/
class User {
private Long id;
private String username;
private String email;
public User() {}
public User(Long id, String username, String email) {
this.id = id;
this.username = username;
this.email = email;
}
@Override
public String toString() {
return "User{id=" + id + ", username='" + username + "', email='" + email + "'}";
}
// Getters
public Long getId() { return id; }
public String getUsername() { return username; }
public String getEmail() { return email; }
}
/**
* 简化版MyBatis - Mapper代理工厂
*/
class MapperProxyFactory {
// 模拟数据库
private static Map<Long, User> database = new HashMap<>();
static {
database.put(1L, new User(1L, "zhangsan", "zhangsan@example.com"));
database.put(2L, new User(2L, "lisi", "lisi@example.com"));
}
@SuppressWarnings("unchecked")
public static <T> T getMapper(Class<T> mapperInterface) {
return (T) Proxy.newProxyInstance(
mapperInterface.getClassLoader(),
new Class[]{mapperInterface},
(proxy, method, args) -> {
// 解析SQL注解
String sql = null;
String sqlType = null;
if (method.isAnnotationPresent(Select.class)) {
sql = method.getAnnotation(Select.class).value();
sqlType = "SELECT";
} else if (method.isAnnotationPresent(Insert.class)) {
sql = method.getAnnotation(Insert.class).value();
sqlType = "INSERT";
} else if (method.isAnnotationPresent(Update.class)) {
sql = method.getAnnotation(Update.class).value();
sqlType = "UPDATE";
} else if (method.isAnnotationPresent(Delete.class)) {
sql = method.getAnnotation(Delete.class).value();
sqlType = "DELETE";
}
if (sql == null) {
throw new RuntimeException("未找到SQL注解");
}
// 解析参数
Map<String, Object> paramMap = parseParams(method, args);
// 执行SQL(模拟)
System.out.println("\n[MyBatis] " + sqlType + ": " + sql);
System.out.println("[MyBatis] 参数: " + paramMap);
// 模拟执行并返回结果
return executeSql(sqlType, paramMap);
}
);
}
private static Map<String, Object> parseParams(Method method, Object[] args) {
Map<String, Object> paramMap = new HashMap<>();
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
if (parameter.isAnnotationPresent(Param.class)) {
String paramName = parameter.getAnnotation(Param.class).value();
paramMap.put(paramName, args[i]);
}
}
return paramMap;
}
private static Object executeSql(String sqlType, Map<String, Object> params) {
switch (sqlType) {
case "SELECT":
Long id = (Long) params.get("id");
if (id != null) {
User user = database.get(id);
System.out.println("[MyBatis] 查询结果: " + user);
return user;
}
String username = (String) params.get("username");
if (username != null) {
User user = database.values().stream()
.filter(u -> u.getUsername().equals(username))
.findFirst().orElse(null);
System.out.println("[MyBatis] 查询结果: " + user);
return user;
}
break;
case "INSERT":
case "UPDATE":
case "DELETE":
System.out.println("[MyBatis] 影响行数: 1");
return 1;
}
return null;
}
}
/**
* 测试MyBatis注解
*/
class MyBatisAnnotationDemo {
public static void main(String[] args) {
// 获取Mapper代理
UserMapper userMapper = MapperProxyFactory.getMapper(UserMapper.class);
// 查询
userMapper.findById(1L);
userMapper.findByUsername("lisi");
// 插入
userMapper.insert(new User(3L, "wangwu", "wangwu@example.com"));
// 更新
userMapper.updateEmail(1L, "new_email@example.com");
// 删除
userMapper.deleteById(2L);
}
}
八、参数校验注解(JSR-303)
package com.example.annotation.validation;
import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* JSR-303 Bean Validation注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface NotNull {
String message() default "不能为null";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface NotEmpty {
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 Email {
String message() default "邮箱格式不正确";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Pattern {
String regexp();
String message() default "格式不匹配";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Min {
long value();
String message() default "值太小";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Max {
long value();
String message() default "值太大";
}
/**
* 用户注册DTO
*/
class UserRegisterDTO {
@NotNull(message = "用户名不能为空")
@NotEmpty(message = "用户名不能为空字符串")
@Size(min = 3, max = 20, message = "用户名长度必须在3-20之间")
@Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "用户名只能包含字母数字下划线")
private String username;
@NotNull(message = "密码不能为空")
@Size(min = 6, max = 20, message = "密码长度必须在6-20之间")
private String password;
@NotNull(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
private String email;
@NotNull(message = "年龄不能为空")
@Min(value = 18, message = "年龄必须大于等于18")
@Max(value = 100, message = "年龄必须小于等于100")
private Integer age;
public UserRegisterDTO(String username, String password, String email, Integer age) {
this.username = username;
this.password = password;
this.email = email;
this.age = age;
}
// Getters
public String getUsername() { return username; }
public String getPassword() { return password; }
public String getEmail() { return email; }
public Integer getAge() { return age; }
}
/**
* 校验结果
*/
class ValidationResult {
private boolean success;
private List<String> errors = new ArrayList<>();
public boolean isSuccess() { return success; }
public void setSuccess(boolean success) { this.success = success; }
public List<String> getErrors() { return errors; }
public void addError(String error) { this.errors.add(error); }
}
/**
* 简化版参数校验器
*/
class Validator {
public static ValidationResult validate(Object obj) throws Exception {
ValidationResult result = new ValidationResult();
result.setSuccess(true);
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
Object value = field.get(obj);
// @NotNull校验
if (field.isAnnotationPresent(NotNull.class)) {
if (value == null) {
result.setSuccess(false);
result.addError(field.getAnnotation(NotNull.class).message());
continue;
}
}
// @NotEmpty校验
if (field.isAnnotationPresent(NotEmpty.class)) {
if (value instanceof String && ((String) value).isEmpty()) {
result.setSuccess(false);
result.addError(field.getAnnotation(NotEmpty.class).message());
continue;
}
}
// @Size校验
if (field.isAnnotationPresent(Size.class) && value instanceof String) {
Size size = field.getAnnotation(Size.class);
int len = ((String) value).length();
if (len < size.min() || len > size.max()) {
result.setSuccess(false);
result.addError(size.message());
}
}
// @Email校验
if (field.isAnnotationPresent(Email.class) && value instanceof String) {
String email = (String) value;
if (!email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$")) {
result.setSuccess(false);
result.addError(field.getAnnotation(Email.class).message());
}
}
// @Pattern校验
if (field.isAnnotationPresent(Pattern.class) && value instanceof String) {
Pattern pattern = field.getAnnotation(Pattern.class);
if (!((String) value).matches(pattern.regexp())) {
result.setSuccess(false);
result.addError(pattern.message());
}
}
// @Min校验
if (field.isAnnotationPresent(Min.class) && value instanceof Number) {
Min min = field.getAnnotation(Min.class);
if (((Number) value).longValue() < min.value()) {
result.setSuccess(false);
result.addError(min.message());
}
}
// @Max校验
if (field.isAnnotationPresent(Max.class) && value instanceof Number) {
Max max = field.getAnnotation(Max.class);
if (((Number) value).longValue() > max.value()) {
result.setSuccess(false);
result.addError(max.message());
}
}
}
return result;
}
}
/**
* 测试参数校验
*/
class ValidationDemo {
public static void main(String[] args) throws Exception {
System.out.println("=== 测试1: 正确的数据 ===");
UserRegisterDTO validUser = new UserRegisterDTO(
"zhangsan", "pass123456", "zhangsan@example.com", 25);
testValidation(validUser);
System.out.println("\n=== 测试2: 用户名太短 ===");
UserRegisterDTO shortUsername = new UserRegisterDTO(
"ab", "pass123456", "zhangsan@example.com", 25);
testValidation(shortUsername);
System.out.println("\n=== 测试3: 邮箱格式错误 ===");
UserRegisterDTO invalidEmail = new UserRegisterDTO(
"zhangsan", "pass123456", "invalid-email", 25);
testValidation(invalidEmail);
System.out.println("\n=== 测试4: 年龄不满足 ===");
UserRegisterDTO youngAge = new UserRegisterDTO(
"zhangsan", "pass123456", "zhangsan@example.com", 16);
testValidation(youngAge);
System.out.println("\n=== 测试5: 多个错误 ===");
UserRegisterDTO multiErrors = new UserRegisterDTO(
"ab", "123", "bad", 10);
testValidation(multiErrors);
}
private static void testValidation(UserRegisterDTO dto) throws Exception {
ValidationResult result = Validator.validate(dto);
if (result.isSuccess()) {
System.out.println("✓ 校验通过");
} else {
System.out.println("✗ 校验失败:");
for (String error : result.getErrors()) {
System.out.println(" - " + error);
}
}
}
}
九、注解实战:自定义权限校验
package com.example.annotation.security;
import java.lang.annotation.*;
import java.lang.reflect.Method;
/**
* 实战案例:基于注解的权限校验系统
*/
// === 权限注解 ===
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequiresPermission {
String[] value(); // 需要的权限
Logical logical() default Logical.AND; // 逻辑关系
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequiresRole {
String[] value(); // 需要的角色
Logical logical() default Logical.AND;
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequiresLogin {
}
enum Logical {
AND, // 所有权限都需要
OR // 只需要其中一个权限
}
/**
* 用户信息
*/
class UserContext {
private String username;
private String[] roles;
private String[] permissions;
public UserContext(String username, String[] roles, String[] permissions) {
this.username = username;
this.roles = roles;
this.permissions = permissions;
}
public String getUsername() { return username; }
public String[] getRoles() { return roles; }
public String[] getPermissions() { return permissions; }
public boolean hasRole(String role) {
if (roles == null) return false;
for (String r : roles) {
if (r.equals(role)) return true;
}
return false;
}
public boolean hasPermission(String permission) {
if (permissions == null) return false;
for (String p : permissions) {
if (p.equals(permission)) return true;
}
return false;
}
}
/**
* 当前用户上下文(ThreadLocal)
*/
class SecurityContext {
private static ThreadLocal<UserContext> context = new ThreadLocal<>();
public static void setUser(UserContext user) {
context.set(user);
}
public static UserContext getUser() {
return context.get();
}
public static void clear() {
context.remove();
}
}
/**
* 权限校验器
*/
class PermissionChecker {
/**
* 检查方法权限
*/
public static boolean check(Method method) {
UserContext user = SecurityContext.getUser();
// 1. 检查登录
if (method.isAnnotationPresent(RequiresLogin.class)) {
if (user == null) {
System.out.println("[权限拒绝] 未登录");
return false;
}
}
// 2. 检查角色
if (method.isAnnotationPresent(RequiresRole.class)) {
RequiresRole requiresRole = method.getAnnotation(RequiresRole.class);
if (!checkRole(user, requiresRole)) {
System.out.println("[权限拒绝] 缺少角色: " +
java.util.Arrays.toString(requiresRole.value()));
return false;
}
}
// 3. 检查权限
if (method.isAnnotationPresent(RequiresPermission.class)) {
RequiresPermission requiresPermission = method.getAnnotation(RequiresPermission.class);
if (!checkPermission(user, requiresPermission)) {
System.out.println("[权限拒绝] 缺少权限: " +
java.util.Arrays.toString(requiresPermission.value()));
return false;
}
}
return true;
}
private static boolean checkRole(UserContext user, RequiresRole requiresRole) {
if (user == null) return false;
String[] requiredRoles = requiresRole.value();
Logical logical = requiresRole.logical();
if (logical == Logical.AND) {
// 需要所有角色
for (String role : requiredRoles) {
if (!user.hasRole(role)) {
return false;
}
}
return true;
} else {
// 只需要其中一个角色
for (String role : requiredRoles) {
if (user.hasRole(role)) {
return true;
}
}
return false;
}
}
private static boolean checkPermission(UserContext user, RequiresPermission requiresPermission) {
if (user == null) return false;
String[] requiredPermissions = requiresPermission.value();
Logical logical = requiresPermission.logical();
if (logical == Logical.AND) {
for (String permission : requiredPermissions) {
if (!user.hasPermission(permission)) {
return false;
}
}
return true;
} else {
for (String permission : requiredPermissions) {
if (user.hasPermission(permission)) {
return true;
}
}
return false;
}
}
}
/**
* 业务服务(带权限控制)
*/
class AdminService {
@RequiresLogin
public void viewProfile() {
System.out.println(" [执行] 查看个人资料");
}
@RequiresRole("ADMIN")
public void manageUsers() {
System.out.println(" [执行] 管理用户");
}
@RequiresPermission({"user:create", "user:update"})
public void createAndUpdateUser() {
System.out.println(" [执行] 创建并更新用户");
}
@RequiresPermission(value = {"user:delete", "user:ban"}, logical = Logical.OR)
public void removeUser() {
System.out.println(" [执行] 移除用户");
}
@RequiresRole("ADMIN")
@RequiresPermission("system:config")
public void modifySystemConfig() {
System.out.println(" [执行] 修改系统配置");
}
}
/**
* 方法拦截器(AOP)
*/
class SecurityInterceptor {
public static Object invoke(Object target, String methodName) throws Exception {
Method method = target.getClass().getMethod(methodName);
System.out.println("\n[拦截器] 调用方法: " + methodName);
// 权限检查
if (!PermissionChecker.check(method)) {
throw new RuntimeException("权限不足");
}
System.out.println("[权限通过]");
// 执行方法
return method.invoke(target);
}
}
/**
* 测试权限系统
*/
class SecurityAnnotationDemo {
public static void main(String[] args) {
AdminService service = new AdminService();
// === 场景1: 未登录用户 ===
System.out.println("=== 场景1: 未登录用户 ===");
SecurityContext.clear();
testInvoke(service, "viewProfile");
// === 场景2: 普通用户 ===
System.out.println("\n=== 场景2: 普通用户 ===");
UserContext normalUser = new UserContext(
"zhangsan",
new String[]{"USER"},
new String[]{"user:view"}
);
SecurityContext.setUser(normalUser);
testInvoke(service, "viewProfile");
testInvoke(service, "manageUsers");
// === 场景3: 管理员(有角色无权限) ===
System.out.println("\n=== 场景3: 管理员(有角色无权限) ===");
UserContext adminNoPermission = new UserContext(
"admin1",
new String[]{"ADMIN"},
new String[]{}
);
SecurityContext.setUser(adminNoPermission);
testInvoke(service, "manageUsers");
testInvoke(service, "modifySystemConfig");
// === 场景4: 超级管理员(有所有权限) ===
System.out.println("\n=== 场景4: 超级管理员 ===");
UserContext superAdmin = new UserContext(
"superadmin",
new String[]{"ADMIN", "SUPER_ADMIN"},
new String[]{"user:create", "user:update", "user:delete", "system:config"}
);
SecurityContext.setUser(superAdmin);
testInvoke(service, "createAndUpdateUser");
testInvoke(service, "modifySystemConfig");
// === 场景5: OR逻辑(只需一个权限) ===
System.out.println("\n=== 场景5: OR逻辑测试 ===");
UserContext partialPermission = new UserContext(
"user1",
new String[]{"USER"},
new String[]{"user:delete"} // 只有delete权限
);
SecurityContext.setUser(partialPermission);
testInvoke(service, "removeUser"); // OR逻辑,应该通过
}
private static void testInvoke(Object service, String methodName) {
try {
SecurityInterceptor.invoke(service, methodName);
} catch (Exception e) {
System.out.println(" [失败] " + e.getMessage());
}
}
}
十、注解最佳实践
10.1 注解设计原则
package com.example.annotation.best;
import java.lang.annotation.*;
/**
* 注解设计最佳实践
*/
public class AnnotationBestPractices {
// ✓ 好的设计: 语义清晰,命名规范
@interface Service {
String value() default "";
}
// ✓ 好的设计: 提供合理的默认值
@interface CacheConfig {
int ttl() default 3600; // 默认1小时
String key() default "";
boolean enabled() default true;
}
// ✓ 好的设计: 使用枚举限制取值
@interface Transaction {
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
}
enum Propagation { REQUIRED, REQUIRES_NEW, SUPPORTS }
enum Isolation { DEFAULT, READ_COMMITTED, REPEATABLE_READ }
// ✗ 不好的设计: 属性过多,难以使用
@interface BadDesign {
String value();
String name();
String description();
String author();
String version();
String date();
String category();
int priority();
boolean enabled();
String[] tags();
// ... 太多属性
}
// ✓ 好的设计: 拆分成多个注解
@interface Metadata {
String author();
String version();
String date();
}
@interface Config {
String name();
String description();
boolean enabled() default true;
}
public static void printBestPractices() {
System.out.println("=== 注解设计最佳实践 ===\n");
System.out.println("1. 命名规范");
System.out.println(" ✓ 使用清晰的名词或动词");
System.out.println(" ✓ 遵循驼峰命名规则");
System.out.println(" ✓ 避免缩写和歧义");
System.out.println("\n2. 属性设计");
System.out.println(" ✓ 提供合理的默认值");
System.out.println(" ✓ 使用枚举限制取值范围");
System.out.println(" ✓ 属性不要过多(建议<5个)");
System.out.println(" ✓ value属性用于最常用的配置");
System.out.println("\n3. 元注解使用");
System.out.println(" ✓ 明确指定@Retention");
System.out.println(" ✓ 明确指定@Target");
System.out.println(" ✓ 需要时添加@Documented");
System.out.println(" ✓ 谨慎使用@Inherited");
System.out.println("\n4. 性能考虑");
System.out.println(" ✓ 缓存反射获取的注解信息");
System.out.println(" ✓ 编译期处理优于运行期");
System.out.println(" ✓ 避免过度使用注解");
System.out.println("\n5. 文档和示例");
System.out.println(" ✓ 添加详细的JavaDoc");
System.out.println(" ✓ 提供使用示例");
System.out.println(" ✓ 说明注解的作用时机");
}
public static void main(String[] args) {
printBestPractices();
}
}
10.2 注解使用场景总结
+---------------------------+---------------------------+
| 使用场景 | 典型注解 |
+---------------------------+---------------------------+
| 依赖注入 | @Autowired, @Resource |
| 事务管理 | @Transactional |
| AOP切面 | @Aspect, @Before, @After |
| Web请求映射 | @RequestMapping, @GetMapping |
| 参数校验 | @NotNull, @Size, @Email |
| ORM映射 | @Entity, @Table, @Column |
| 缓存管理 | @Cacheable, @CacheEvict |
| 异步处理 | @Async |
| 定时任务 | @Scheduled |
| 权限控制 | @PreAuthorize, @RolesAllowed |
| API文档 | @ApiOperation, @ApiParam |
| 序列化控制 | @JsonProperty, @JsonIgnore |
| 测试 | @Test, @Before, @After |
| 代码生成 | @Data, @Builder (Lombok) |
+---------------------------+---------------------------+
总结
核心知识点回顾
本文深入探讨了Java注解机制,主要内容包括:
-
注解基础
- Java内置注解(@Override、@Deprecated等)
- 元注解(@Retention、@Target、@Documented等)
- 自定义注解语法与规范
-
注解处理
- 运行时注解处理器(反射)
- 编译期注解处理器(APT)
- 注解的生命周期
-
框架应用
- Spring框架的IoC、AOP、MVC注解
- MyBatis的SQL映射注解
- JSR-303参数校验注解
-
实战案例
- Excel导出注解设计
- 权限校验注解系统
- 性能测试注解处理器
注解 vs 配置文件
| 维度 | 注解 | XML配置文件 |
|---|---|---|
| 简洁性 | 高 | 低 |
| 耦合度 | 高(侵入代码) | 低(外部配置) |
| 维护性 | 分散在代码中 | 集中管理 |
| 类型安全 | 编译期检查 | 运行期检查 |
| 灵活性 | 低(需重新编译) | 高(可动态修改) |
学习建议
学习路径:
内置注解 → 元注解 → 自定义注解 → 注解处理器 → 框架源码
↓ ↓ ↓ ↓ ↓
基础语法 生命周期 实战案例 反射/APT Spring/MyBatis
进阶方向:
- 深入研究Spring注解原理
- 学习APT开发(如Lombok源码)
- 掌握字节码增强技术
- 理解JSR规范(如JSR-303、JSR-250)