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 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 {}
// 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 create(@RequestParam String name){
User u = userService.createUser(name);
return ResponseEntity.status(HttpStatus.CREATED).body(u);
}
@GetMapping("/{id}")
public ResponseEntity get(@PathVariable Long id){
return ResponseEntity.of(Optional.ofNullable(userService.getUser(id)));
}
}
posted @ 2025-09-25 14:35  wzzkaifa  阅读(11)  评论(0)    收藏  举报