什么是注解
注解(Annotation)是 Java 5 引入的一种元数据机制,它本身不影响代码逻辑,但可以被编译器、开发工具或运行时框架读取和使用!
// 最简单的注解例子
@Override // 这个就是注解哦!
public String toString() {
return ;
}
Java 注解是 Java 5 引入的元数据机制,用于向编译器或框架提供额外信息。注解的基本概念、内置注解、元注解及自定义注解方法。重点阐述了注解在编译检查、代码生成及运行时处理中的作用,特别是在 Spring Boot 框架中通过反射机制实现依赖注入、URL 映射等功能的重要性。文章对比了注解与普通注释的区别,说明了缺少关键注解可能导致的服务无法管理、空指针异常等问题,并提供了自定义注解的实践示例。
注解(Annotation)是 Java 5 引入的一种元数据机制,它本身不影响代码逻辑,但可以被编译器、开发工具或运行时框架读取和使用!
// 最简单的注解例子
@Override // 这个就是注解哦!
public String toString() {
return ;
}
@Override // 告诉编译器:我要重写父类方法,帮我检查对不对!
public void run() {
System.out.println("曼波在奔跑!");
}
// Spring Boot 中常见的 @Getter
// 自动生成 getter 方法
@Setter // 自动生成 setter 方法
public class User {
private String name;
private int age;
}
@RestController // 告诉 Spring:这是一个控制器!
@RequestMapping("/api") // 映射 URL 路径
public class MyController {
@Autowired // 自动注入依赖
private UserService userService;
@GetMapping("/hello") // 处理 GET 请求
public String hello() {
return "Hello 曼波!";
}
}
@Override // 检查方法重写
@Deprecated // 标记过时的方法
@SuppressWarnings("unchecked") // 抑制警告
@Target(ElementType.METHOD) // 注解可以用在哪里
@Retention(RetentionPolicy.RUNTIME) // 注解保留到什么时候
@Documented // 包含在 Javadoc 中
@Inherited // 子类可以继承
// 曼波教你创建自己的注解!
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ManboAnnotation {
String value() default "曼波默认值"; // 注解属性
int priority() default 1;
}
// Spring 是怎么知道 @RestController 是控制器的呢?
// 1. 扫描所有类
// 2. 检查是否有 @RestController 注解
// 3. 如果有,就创建实例并管理起来
@RestController // ← Spring 看到这个就知道要特殊处理!
public class HelloController {
// 魔法发生在这里~
}
// 🌸 声明 Bean 的注解
@Component // 通用组件
@Repository // 数据访问层
@Service // 业务层
@Controller // 控制层
@RestController // REST 控制层
// 🔗 依赖注入
@Autowired // 自动装配
@Resource // 按名称装配
// 🌐 Web 相关
@RequestMapping
@GetMapping
@PostMapping
@PathVariable
@RequestParam
// ⚙️ 配置相关
@Configuration
@Bean
@Value
@PropertySource
// 1. 定义注解:记录方法执行时间
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TimeLog {
String name() default "";
}
// 2. 使用注解
public class Calculator {
@TimeLog(name = "加法计算")
public int add(int a, int b) {
return a + b;
}
@TimeLog(name = "乘法计算")
public int multiply(int a, int b) {
return a * b;
}
}
// 3. 处理注解(通过反射)
public class AnnotationProcessor {
public static void process(Object obj) throws Exception {
Class<?> clazz = obj.getClass();
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(TimeLog.class)) {
TimeLog annotation = method.getAnnotation(TimeLog.class);
System.out.println("开始执行:" + annotation.name());
long start = System.currentTimeMillis();
method.invoke(obj, 10, 20); // 调用方法
long end = System.currentTimeMillis();
System.out.println("执行耗时:" + (end - start) + "ms");
}
}
}
}
注解可不仅仅是'提醒一下'的小标签哦!它是有实际功能的!
// ❌ 没有注解 - Spring 完全无视这个类
public class UserService {
public void saveUser() {
System.out.println("保存用户");
}
}
// ✅ 有注解 - Spring 会管理这个类
@Service // ← 这个注解告诉 Spring:请管理我!
public class UserService {
public void saveUser() {
System.out.println("保存用户");
}
}
问题:没有 @Service,Spring 根本不知道这个类的存在,不会创建实例,其他类也无法注入它!
// ❌ 没有 @Autowired - Spring 不知道要注入
public class UserController {
private UserService userService; // 这里是 null!
public void addUser() {
userService.saveUser(); // ❌ 空指针异常!
}
}
// ✅ 有 @Autowired - Spring 自动注入
public class UserController {
@Autowired // ← 告诉 Spring:请把 UserService 给我!
private UserService userService;
public void addUser() {
userService.saveUser(); // ✅ 正常执行
}
}
// ❌ 没有注解 - 浏览器访问不到
public class HelloController {
public String hello() {
return "Hello 曼波!";
}
}
// ✅ 有注解 - 可以正常访问
@RestController
public class HelloController {
@GetMapping("/hello") // ← 告诉 Spring:/hello 请求找我!
public String hello() {
return "Hello 曼波!";
}
}
问题:访问 http://localhost:8080/hello 会得到 404 错误!
让曼波用对比表格说明:
| 特性 | 普通标签(注释) | Java 注解 |
|---|---|---|
| 谁看? | 程序员看 | 程序看(编译器/框架) |
| 有作用吗? | 无实际作用 | 有实际作用 |
| 例子 | // 这是一个 Service 类 | @Service |
| 结果 | 只是提示 | Spring 会创建实例 |
// 这个只是给人看的提示,程序完全忽略
// TODO: 这里需要改成 Service
public class UserService {
// ...
}
// 这个是给 Spring 看的指令,必须执行!
@Service // ← Spring 看到这个就会行动!
public class UserService {
// ...
}
注解背后有强大的机制在运作:
// ❌ 没有注解 = 默默坐在餐厅,没人理你
顾客 小明;
// 结果:饿肚子!
// ✅ 有注解 = 举手喊'服务员!'
@叫服务员 // ← 就像 @Autowired
顾客 小明;
// 结果:服务员过来为你服务!
// ❌ 没有注解 = 包裹没写地址
包裹 我的包裹;
// 结果:快递员不知道送到哪里
// ✅ 有注解 = 包裹写了详细地址
@地址("北京市海淀区") // ← 就像 @RequestMapping
包裹 我的包裹;
// 结果:准确送达!
// ❌ 没有注解 = 原料堆在仓库
原料 钢材;
// 结果:不会自动变成产品
// ✅ 有注解 = 原料贴上'加工指令'
@加工成("汽车零件") // ← 就像 @Component
原料 钢材;
// 结果:流水线自动加工!
三句话总结:
实际后果:
建议:
// 记住这些必须加的注解!
@SpringBootApplication // 启动类必须加
@Component/@Service/@Repository // 业务类必须加
@Autowired // 注入依赖必须加
@RestController + @GetMapping // 控制器必须加
所以记住,注解就像是给 Spring 的工作指令,没有指令,Spring 就不知道该做什么了!就像没有菜谱,厨师也不知道怎么做菜一样。
@ManboLog 注解,记录方法调用日志@ManboRestController注解的本质是'约定大于配置',Spring Boot 通过注解让开发变得超级简单!就像搭积木一样,标注一下,功能就有了。
记住:注解不是魔法,是聪明的设计! 理解了反射机制,你就看透了注解的本质!

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online