Spring / Spring Boot 常用注解

核心原则(先看这段)

  • 把行为(业务)放在 Service 层,事务/缓存/异步等注解一般放在 Service 层,不要把复杂逻辑放到 Controller。

  • 首选构造器注入(constructor injection),比字段注入更利于测试与不可变性。

  • 注解很多都是"语义化的标记 + 框架在运行时的处理",理解背后的代理/生命周期很重要(例如 @Transactional 基于 AOP 代理,自调用不会触发代理逻辑)。

核心/启动与配置注解

复制代码
@SpringBootApplication // 等价于 @Configuration + @EnableAutoConfiguration + @ComponentScan(默认扫描启动类包及子包)
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
  • @Configuration:Java 配置类(替代 XML)。

  • @Bean:方法级别把返回对象注册为 Spring Bean(可设置 init/destroy)。

  • @ComponentScan:定制扫描包路径(启动类包位置很关键,建议把主类放在根包)。

  • @EnableConfigurationProperties:启用 @ConfigurationProperties 绑定(在 Spring Boot 中,直接将 @ConfigurationProperties 标注成 @Component 也可被扫描到)。

  • @ConfigurationProperties(prefix="..."):批量强类型注入配置(推荐用于复杂/层级配置,支持校验 @Validated)。

示例(YAML + 配置类):

复制代码
# application.yml
app:
  name: demo
  timeout: 30
  nested:
    enabled: true

@Component
@ConfigurationProperties(prefix = "app")
@Validated
public class AppProperties {
    @NotBlank
    private String name;
    private int timeout;
    private Nested nested = new Nested();
    // getters/setters
    public static class Nested { private boolean enabled; /* getter/setter */ }
}

组件(stereotype)注解与区别

  • @Component:通用组件(任何层通用)。

  • @Service:业务层语义化(仅为语义,便于识别)。

  • @Repository:持久层语义化,且启用 异常翻译(把 JPA/Hibernate 的异常翻译为 Spring 的 DataAccessException)。

  • @Controller:MVC 控制器,通常返回视图(与 @ResponseBody 组合可返回 JSON)。

  • @RestController:@Controller + @ResponseBody,更常用于 REST API。

何时用?按层次用对应注解(可读性和工具/监控的好处)。

依赖注入 / Bean 选择 / Scope / 生命周期

  • 注入方式对比(推荐):

    • 构造器注入(推荐):支持 final,利于单元测试。

    • Setter 注入:有状态或可选依赖时可用。

    • 字段注入(@Autowired 在字段上):不推荐(难测、不可 final)。

      @Service
      public class MyService {
      private final UserRepository repo;
      public MyService(UserRepository repo) { this.repo = repo; } // 自动注入(Spring 4.3+)
      }

  • @Autowired(按类型注入),@Qualifier("name") 或 @Primary(用于同类型多个 Bean);

  • @Resource(JSR-250,按名称优先);

  • @Value("${xxx}")(注入单个配置值);

  • @ConfigurationProperties(批量注入复杂配置);

Bean scope:

  • @Scope("singleton")(默认)

  • @Scope("prototype")(每次请求新实例)

  • 还有 request、session(web 场景)等

生命周期:

  • @PostConstruct、@PreDestroy(JSR)

  • 或在 @Bean(initMethod="...", destroyMethod="...") 指定

  • InitializingBean / DisposableBean(接口)

    示例:

    @PostConstruct
    public void init(){ /* init work / }
    @PreDestroy
    public void cleanup(){ /
    release */ }

Web / Controller 相关注解(常用)

  • 路由映射:@RequestMapping、@GetMapping、@PostMapping、@PutMapping、@DeleteMapping。

  • 参数绑定:@PathVariable、@RequestParam、@RequestBody、@RequestHeader、@CookieValue。

  • 返回:@ResponseBody(将返回对象序列化为 JSON) → @RestController 更常用。

  • 状态码:@ResponseStatus(HttpStatus.CREATED)。

  • 验证:@Valid(与 Bean Validation 联动) + DTO 上加注解 @NotNull/@Size...。

  • 异常处理:@ControllerAdvice + @ExceptionHandler(全局异常/统一返回)或 @RestControllerAdvice。

示例:

复制代码
@RestController
@RequestMapping("/users")
public class UserController {
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public UserDto create(@Valid @RequestBody CreateUserDto dto) { ... }
}

数据访问与事务(重要)

  • @Repository(DAO层) + JPA @Entity / MyBatis 接口等。

  • @Transactional(关键点):

    • 放在 Service 层方法上最合适(控制事务边界)。

    • 常用属性:propagation、isolation、readOnly、rollbackFor。

    • 注意:@Transactional 基于代理(AOP),内部自调用不会触发事务(self-invocation)

      @Service
      public class OrderService {
      @Transactional(rollbackFor = Exception.class)
      public void placeOrder(OrderDto dto){ ... }
      }

常见坑:

  • 在同一个类里面 public methodA() 调 private methodB() 并给 methodB 标注 @Transactional,事务不会生效(因为代理不会拦截内部调用)。解决:把方法拆到另一个 Bean,或使用 AopContext.currentProxy() (不常用)。

AOP(切面)相关注解

  • @Aspect(切面类) + @Before / @After / @AfterReturning / @Around / @Pointcut。

  • 典型用途:日志、监控、权限校验、限流、重试等。

    @Aspect
    @Component
    public class LoggingAspect {
    @Pointcut("execution(* com.example.service..*(..))")
    public void serviceMethods() {}

    复制代码
      @Around("serviceMethods()")
      public Object log(ProceedingJoinPoint pjp) throws Throwable {
          long t = System.currentTimeMillis();
          Object ret = pjp.proceed();
          System.out.println("took " + (System.currentTimeMillis() - t));
          return ret;
      }

    }

异步 / 调度 / 缓存 / 安全(常见功能注解)

  • 异步:@EnableAsync(配置类) + @Async(方法) → 返回 void / Future / CompletableFuture。注意自调用失效

  • 调度:@EnableScheduling + @Scheduled(cron = "...")。

  • 缓存:@EnableCaching + @Cacheable / @CacheEvict / @CachePut。

  • 方法级安全:@PreAuthorize("hasRole('ADMIN')") / @Secured,配合 @EnableMethodSecurity(或旧版 @EnableGlobalMethodSecurity)。

示例(异步):

复制代码
@Configuration
@EnableAsync
public class AsyncConfig {}
@Service
public class MailService {
    @Async
    public CompletableFuture<Void> sendAsync(...) { ... }
}

条件化 & 自动配置注解(Spring Boot 自动化)

  • @ConditionalOnProperty(name="...", havingValue="..."):基于配置决定是否装配某 Bean。

  • @ConditionalOnClass:当类在 classpath 上时才生效(常用在 starter/自动配置中)。

  • @ConditionalOnMissingBean:容器中没有指定类型的 Bean 时才创建默认 bean。

  • @Profile("dev"):按 profile 加载(spring.profiles.active=dev)。

示例(有默认实现但允许覆盖):

复制代码
@Configuration
@ConditionalOnClass(SomeClient.class)
public class AutoConfig {
    @Bean
    @ConditionalOnMissingBean
    public MyClient myClient(){ return new DefaultMyClient(); }
}

测试相关注解(常见)

  • @SpringBootTest:集成测试,启动整个上下文(慢)。

  • @WebMvcTest(controllers = ...):只加载 Web 层(适合 Controller 测试)。

  • @DataJpaTest:只加载 JPA 相关组件(内存数据库)。

  • @MockBean:在 Spring 容器中替换某个 Bean 为 mock。

  • @TestConfiguration:测试专用配置类。

常见坑、注意事项与最佳实践(实战派)

  1. 优先构造器注入(可用 final,更安全)。

  2. @Transactional 放在 public 方法上且不要依赖自调用来触发事务。

  3. Controller 层只做参数校验/返回,不做事务处理和复杂业务(业务放 Service)。

  4. 使用 @ConfigurationProperties 管理复杂配置,@Value 仅用于单值注入。

  5. @Repository 会做异常翻译(推荐持久层使用)。

  6. @RestControllerAdvice + @ExceptionHandler 做统一异常处理和统一响应结构。

  7. 生产环境建议对定时任务、异步线程池、缓存策略做合理配置与监控。

  8. 用 @Profile 管理 dev/test/prod 配置差异。

  9. 注意 @Async / @Transactional/@Cacheable 等基于代理的注解,均受自调用影响。

速查小表(快速记忆)

  • 启动:@SpringBootApplication

  • 配置:@Configuration / @Bean / @ConfigurationProperties

  • 组件:@Component / @Service / @Repository / @Controller / @RestController

  • 注入:@Autowired / @Qualifier / @Value / 构造器注入

  • Web:@GetMapping / @PostMapping / @RequestBody / @PathVariable

  • 事务:@Transactional(放 Service)

  • AOP:@Aspect / @Around / @Pointcut

  • 异步:@EnableAsync + @Async

  • 调度:@EnableScheduling + @Scheduled

  • 缓存:@EnableCaching + @Cacheable

  • 条件/自动配置:@ConditionalOnProperty / @ConditionalOnClass / @ConditionalOnMissingBean

  • 测试:@SpringBootTest / @WebMvcTest / @MockBean

代码示例:Controller → Service → Repository + 配置属性(可拷贝运行)

复制代码
// Application.java
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

// AppProperties.java
@Component
@ConfigurationProperties(prefix = "app")
@Validated
public class AppProperties {
    @NotBlank private String name;
    private int timeout;
    // getters/setters
}

// UserEntity.java
@Entity
@Table(name = "users")
public class User {
    @Id @GeneratedValue private Long id;
    private String username;
    // getters/setters
}

// UserRepository.java (Spring Data JPA example)
@Repository
public interface UserRepository extends JpaRepository<User, Long> {}

// UserService.java
@Service
public class UserService {
    private final UserRepository userRepository;
    public UserService(UserRepository userRepository) { this.userRepository = userRepository; }

    @Transactional
    public User createUser(String username) {
        User u = new User(); u.setUsername(username);
        return userRepository.save(u);
    }

    @Transactional(readOnly = true)
    public User getUser(Long id){ return userRepository.findById(id).orElse(null); }
}

// UserController.java
@RestController
@RequestMapping("/users")
public class UserController {
    private final UserService userService;
    private final AppProperties props;
    public UserController(UserService userService, AppProperties props){
        this.userService = userService; this.props = props;
    }

    @PostMapping
    public ResponseEntity<User> create(@RequestParam String name){
        User u = userService.createUser(name);
        return ResponseEntity.status(HttpStatus.CREATED).body(u);
    }

    @GetMapping("/{id}")
    public ResponseEntity<User> get(@PathVariable Long id){
        return ResponseEntity.of(Optional.ofNullable(userService.getUser(id)));
    }
}
相关推荐
途经六月的绽放2 小时前
Docker Compose 从入门到实践
java·docker
用户6120414922132 小时前
支持eclipse+idea+mysql5和8的javaweb学生信息管理系统
java·javascript·后端
城管不管2 小时前
SpringBoot与反射
java·开发语言·前端
我不是混子2 小时前
说说建造者模式
java·后端
用户4099322502122 小时前
PostgreSQL UPDATE语句怎么玩?从改邮箱到批量更新的避坑技巧你都会吗?
后端·ai编程·trae
我是谁的程序员2 小时前
前端调试工具有哪些?常用前端调试工具推荐、前端调试工具对比
后端
一直_在路上2 小时前
Go语言架构实践:构建临床ePRO高性能内存数据网格,应对海量并发挑战
后端
一 乐3 小时前
智慧外贸平台|基于Java+vue的智慧外贸平台系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·外贸服务系统