Spring 注解开发指南

本文系统整理 Spring 框架中的核心注解,覆盖组件注册、依赖注入、Web MVC、Spring Boot、AOP、事务等常见场景,帮助开发者快速查阅和正确使用。


第一章 注解基础:元注解(Meta Annotations)

Java 注解(Annotation)是代码的元数据。Spring 大量使用注解替代 XML 配置。以下四个元注解用于定义其他注解:

元注解作用
@Target指定该注解可以放在哪里(类、方法、字段等)
@Retention指定注解保留到哪个阶段(源码、字节码、运行时)
@Documented是否将注解包含在 Javadoc 中
@Inherited子类是否继承父类的该注解
Java
@Target(ElementType.TYPE)       // 只能用在类上
@Retention(RetentionPolicy.RUNTIME) // 运行时仍保留(反射可读)
public @interface MyAnnotation {
    String value() default "";
}

Spring 的很多注解(如 @Component)本身就是被 @Target@Retention 修饰过的,我们直接使用即可。


第二章 组件注册与依赖注入

2.1 声明 Bean:@Component 系列

Spring 管理的对象称为 Bean。将一个类交给 Spring 容器管理,最常用的方式是在类上添加以下注解之一:

注解适用层语义
@Component通用通用的 Spring 组件
@ServiceService 层业务逻辑层(语义更明确)
@RepositoryDao 层数据访问层(同时提供持久层异常转换)
@ControllerWeb 层控制器层(配合 @RequestMapping 处理请求)
Java
@Service  // 标注当前类是 Service 层的 Bean
public class UserService {
    public String getUser() {
        return "用户信息";
    }
}
注意:这四个注解功能完全等价,Spring 都能扫描到。区分它们只是为了语义清晰,方便开发者快速理解类的职责。

2.2 依赖注入:@Autowired

@Autowired 由 Spring 提供,按类型(by type) 自动注入依赖。

Java
@RestController
public class UserController {

    @Autowired
    private UserService userService;  // Spring 自动注入 UserService 的实例

    @GetMapping("/user")
    public String getUser() {
        return userService.getUser();
    }
}

注入方式有三种:

Java
@Service
public class UserServiceImpl implements UserService {
    // 方式一:字段注入(最简洁,最常用)
    @Autowired
    private UserMapper userMapper;

    // 方式二:Setter 注入
    private RoleMapper roleMapper;
    @Autowired
    public void setRoleMapper(RoleMapper roleMapper) {
        this.roleMapper = roleMapper;
    }

    // 方式三:构造器注入(Spring 官方推荐,便于测试和不可变设计)
    private final LogMapper logMapper;
    @Autowired  // 如果类只有一个构造器,可以省略 @Autowired
    public UserServiceImpl(LogMapper logMapper) {
        this.logMapper = logMapper;
    }
}
推荐:当依赖是必需的且在对象生命周期内不变时,优先使用构造器注入;字段注入最简洁但在单元测试中不易 mock。

@Autowired 的特殊配置:

Java
@Autowired(required = false)  // 找不到 Bean 时不报错(字段保持 null)
private MailService mailService;

2.3 按名称注入:@Qualifier

如果同一类型有多个 Bean,@Autowired 会因不知道注入哪个而报错。此时配合 @Qualifier 指定 Bean 名称:

Java
@Component
public class SmsSender implements MessageSender { }

@Component("emailSender")  // 自定义 Bean 名称
public class EmailSender implements MessageSender { }

@RestController
public class NotificationController {

    @Autowired
    @Qualifier("emailSender")  // 指定注入名为 "emailSender" 的 Bean
    private MessageSender messageSender;
}

2.4 @Primary:首选 Bean

当同一类型有多个 Bean 时,用 @Primary 标记其中一个为首选,@Autowired 默认注入它:

Java
@Component
@Primary  // 没有 @Qualifier 时默认注入这个
public class SmsSender implements MessageSender { }

2.5 @Resource(JSR-250):按名称注入

@Resource 是 Java 标准注解(非 Spring 专有),默认按名称(by name) 注入:

Java
@Resource(name = "userService")  // 按名称注入
private UserService userService;

// 不指定 name 时,以字段名作为查找名称
@Resource
private UserService userService; // 先按名称查找,找不到再按类型

2.6 Bean 作用域:@Scope

Java
@Component
@Scope("singleton")     // 单例(默认),整个容器只创建一个实例
// @Scope("prototype")  // 原型,每次获取都创建新实例
// @Scope("request")    // 每个 HTTP 请求创建一个(Web 容器中)
// @Scope("session")    // 每个 HTTP Session 创建一个(Web 容器中)
public class UserService { }

2.7 延迟加载:@Lazy

Java
@Component
@Lazy  // 第一次使用时才创建,而不是容器启动时就创建
public class HeavyService { }

第三章 Spring Web MVC 注解

3.1 @RestController@Controller

Java
@RestController  // = @Controller + @ResponseBody(所有方法返回值直接作为响应体)
public class UserController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello World";  // 直接返回字符串,不解析为视图
    }
}
  • @Controller:标识一个类是 MVC 控制器,返回值通常解析为视图页面(JSP / Thymeleaf)。
  • @RestController:是 @Controller@ResponseBody 的组合注解。每个方法的返回值直接写入 HTTP 响应体(通常为 JSON),适合前后端分离的 API 开发。
Java
@Controller  // 传统 MVC:返回视图页面
public class PageController {
    @GetMapping("/index")
    public String index(Model model) {
        model.addAttribute("name", "张三");
        return "index";  // 解析为 index.html 模板
    }
}

3.2 请求映射注解

注解说明
@RequestMapping通用请求映射,可指定任意方法(GET、POST 等)
@GetMapping简写 @RequestMapping(method = RequestMethod.GET)
@PostMapping简写 @RequestMapping(method = RequestMethod.POST)
@PutMapping简写 @RequestMapping(method = RequestMethod.PUT)
@DeleteMapping简写 @RequestMapping(method = RequestMethod.DELETE)
@PatchMapping简写 @RequestMapping(method = RequestMethod.PATCH)
Java
@RestController
@RequestMapping("/users")  // 类级别:统一前缀
public class UserController {

    @GetMapping("/{id}")        // GET /users/1
    public User get(@PathVariable Long id) { return ...; }

    @PostMapping                // POST /users
    public User create(@RequestBody User user) { return ...; }

    @PutMapping("/{id}")        // PUT /users/1
    public User update(@PathVariable Long id, @RequestBody User user) { return ...; }

    @DeleteMapping("/{id}")     // DELETE /users/1
    public void delete(@PathVariable Long id) { ... }
}

3.3 参数绑定注解

注解作用
@RequestParam绑定 URL 查询参数(?name=value)
@RequestBody绑定请求体中的 JSON/XML 数据
@PathVariable绑定 URL 路径中的变量(/users/{id})
@RequestHeader绑定请求头
@CookieValue绑定 Cookie
@ModelAttribute绑定表单数据到对象(常用于传统 MVC)
@SessionAttribute绑定 Session 中的属性值
@RequestAttribute绑定 Request 作用域中的属性值
Java
@RestController
public class DemoController {

    // @RequestParam: 处理 ?page=1&size=10
    @GetMapping("/list")
    public String list(@RequestParam(defaultValue = "1") int page,
                       @RequestParam(defaultValue = "10") int size) {
        return "page=" + page + ", size=" + size;
    }

    // @PathVariable: 处理 /users/123
    @GetMapping("/users/{id}")
    public String getUser(@PathVariable Long id) {
        return "userId=" + id;
    }

    // @RequestBody: 接收 JSON 请求体
    @PostMapping("/users")
    public String createUser(@RequestBody User user) {
        return "created: " + user.getName();
    }

    // @RequestHeader: 获取请求头
    @GetMapping("/info")
    public String info(@RequestHeader("User-Agent") String userAgent) {
        return "UA=" + userAgent;
    }

    // @SessionAttribute: 获取 Session 中的用户信息
    @GetMapping("/profile")
    public String profile(@SessionAttribute(value = "currentUser", required = false) User user) {
        return user != null ? user.getName() : "未登录";
    }
}

3.4 响应处理注解

@ResponseBody:将方法返回值直接写入 HTTP 响应体(Spring 自动将对象转为 JSON):

Java
@Controller
public class UserController {
    @GetMapping("/user")
    @ResponseBody  // 不加的话会去查找 user.html 视图
    public User getUser() {
        return new User("张三", 18);
    }
}

@ResponseStatus:指定响应状态码:

Java
@ResponseStatus(HttpStatus.CREATED)  // 返回 201
@PostMapping("/users")
public User create(@RequestBody User user) { ... }

3.5 全局异常处理注解

Java
@RestControllerAdvice  // = @ControllerAdvice + @ResponseBody
public class GlobalExceptionHandler {

    @ExceptionHandler(ArithmeticException.class)
    public Result handleArithmetic(ArithmeticException e) {
        return Result.error("数学运算异常:" + e.getMessage());
    }

    @ExceptionHandler(Exception.class)  // 兜底处理
    public Result handleException(Exception e) {
        return Result.error("服务器内部错误");
    }
}
注解作用
@ControllerAdvice定义全局控制器增强(异常处理、数据绑定等)
@RestControllerAdvice@ControllerAdvice + @ResponseBody
@ExceptionHandler处理指定类型的异常

第四章 Spring Boot 注解

:关于 @SpringBootApplication 启动原理、条件装配注解 (@ConditionalXxx) 以及配置读取机制,已统一整理至 《Spring Boot 核心开发指南》。这里仅保留 Web 组件与生命周期相关注解。

4.1 @ServletComponentScan

在 Spring Boot 启动类上使用,扫描 @WebServlet@WebFilter@WebListener 注解:

Java
@SpringBootApplication
@ServletComponentScan  // 扫描 Filter、Servlet 等
public class Application { }

第五章 事务注解:@Transactional

本章侧重 @Transactional 注解速查。事务的 ACID、隔离级别、JDBC/MyBatis 协作、传播行为场景、失效排查等系统内容,请参阅 《Java 数据库事务实战》

5.1 基本用法

Java
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LogMapper logMapper;

    @Transactional  // 该方法中的所有数据库操作在同一个事务中执行
    public void transfer(Long fromId, Long toId, BigDecimal amount) {
        userMapper.deduct(fromId, amount);    // 扣钱
        userMapper.add(toId, amount);         // 加钱
        logMapper.insert(new Log("转账成功")); // 记录日志
        // 如果任意一步失败,所有操作回滚
    }
}

5.2 常用属性

Java
@Transactional(
    propagation = Propagation.REQUIRED,  // 事务传播行为(默认:有则加入,无则新建)
    isolation = Isolation.READ_COMMITTED, // 事务隔离级别
    timeout = 30,                        // 超时秒数
    rollbackFor = Exception.class        // 遇到哪些异常时回滚(默认只回滚 RuntimeException)
)
public void doSomething() { ... }

事务传播行为(propagation):

取值说明
REQUIRED(默认)当前有事务则加入,没有则新建
REQUIRES_NEW不管有没有事务,都创建一个新事务
SUPPORTS有事务则加入,没有则以非事务方式执行
MANDATORY必须在已有事务中执行,否则抛异常
NEVER必须以非事务方式执行,有事务则抛异常
NOT_SUPPORTED以非事务方式执行,挂起当前事务
NESTED嵌套事务(JDBC 的 Savepoint 机制)
注意@Transactional 默认只对 RuntimeException(非受检异常)回滚,对受检异常(Exception 中的非 RuntimeException 子类)不会回滚。如需回滚所有异常,设置 rollbackFor = Exception.class

5.3 注意事项

  • @Transactional 建议优先加在 public 方法上,这是最稳妥、最通用的写法。private 方法稳定不会生效;在 Spring 6 / Boot 3 的类代理场景下,protected 和包级可见方法不应一概而论,但实战中仍建议统一使用 public 方法声明事务边界。
  • 在同一个类中,方法 A(有事务)调用方法 B(有事务),B 的事务不会生效(Spring AOP 代理限制)。
  • 正确用法:将事务方法放在不同的 Service 中调用,或通过 AopContext.currentProxy() 自调用。

第六章 注解组合与最佳实践

6.1 Spring 的组合注解(Composed Annotations)

Spring 大量使用组合注解设计,即用一个注解封装多个注解的功能。

组合注解包含的注解
@SpringBootApplication@Configuration + @EnableAutoConfiguration + @ComponentScan
@RestController@Controller + @ResponseBody
@GetMapping@RequestMapping(method = GET)
@RestControllerAdvice@ControllerAdvice + @ResponseBody

6.2 自定义组合注解

你可以像 Spring 一样,把常用的注解组合起来:

Java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Controller
@ResponseBody
public @interface MyRestController {
    @AliasFor(annotation = Controller.class, attribute = "value")
    String value() default "";
}

6.3 常见误区与建议

误区正确做法
private 方法上加 @Transactional@Transactional 只在 public 方法上生效
在 Controller 层加 @Transactional事务应加在 Service 层的方法上
@Autowired 字段用 private可以,但字段注入在测试中不方便,优先构造器注入
所有 @Component 都使用 @Component按分层使用 @Service@Repository@Controller 语义更清晰
在循环依赖中使用字段注入解决应重构代码消除循环依赖,而非依赖 @Lazy 绕过

总结

本文档整理了 Spring 开发中最常用的注解,从组件注册、Web 开发、自动配置到事务和 AOP。建议与以下文档配合阅读: