Spring Boot 是一个基于 Spring 框架的项目,它通过简化配置来帮助开发者快速构建微服务和其他应用程序。在 Spring Boot 中,注解(Annotations)扮演着非常重要的角色,它们用于减少配置和提高代码的可读性。以下是一些常用的 Spring Boot 注解及其详解:
@SpringBootApplication
- 组合了
@Configuration、@EnableAutoConfiguration和@ComponentScan注解。 - 表明该类是一个 Spring Boot 应用的主类。
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MyApp { public static void main(String[] args) { SpringApplication.run(MyApp.class, args); } }- 组合了
@RestController
- 组合了
@Controller和@ResponseBody注解。 - 表明该类是一个控制器,并且所有的方法返回值都将作为 HTTP 响应的正文。
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.GetMapping; @RestController public class MyController { @GetMapping("/hello") public String hello() { return "Hello, World!"; } }- 组合了
@RequestMapping
- 将 HTTP 请求映射到处理器方法。
- 可以指定请求类型和路径。
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class MyController { @RequestMapping(value = "/greeting", method = RequestMethod.GET) public String greeting() { return "greeting"; } }@GetMapping / @PostMapping / @PutMapping / @DeleteMapping
- 特定类型的
@RequestMapping快捷方式。
@GetMapping("/users") public List<User> getAllUsers() { // ... } @PostMapping("/users") public User createUser(@RequestBody User user) { // ... } @PutMapping("/users/{id}") public User updateUser(@PathVariable Long id, @RequestBody User user) { // ... } @DeleteMapping("/users/{id}") public void deleteUser(@PathVariable Long id) { // ... }- 特定类型的
@Autowired
- 自动注入依赖的组件。可以用于字段、构造器、设置方法和普通方法。
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserService { private final UserRepository userRepository; @Autowired public UserService(UserRepository userRepository) { this.userRepository = userRepository; } // ... }@Service
- 用于标注服务层组件,通常用于业务逻辑处理。
@Service public class UserService { // ... }@Repository
- 用于标注数据访问组件,即DAO组件,表明该类用于数据库操作。
import org.springframework.stereotype.Repository; @Repository public interface UserRepository extends JpaRepository<User, Long> { // ... }@Component
- 用于标注组件,表明该类由 Spring 管理,通常用于非服务层和非数据层的组件。
@Component public class MyComponent { // ... }@Configuration
- 用于定义配置类,可以替代传统的XML配置文件,通常用于定义Bean的创建。
@Configuration public class AppConfig { @Bean public MyBean myBean() { return new MyBean(); } }@Bean
- 在配置类中声明一个 Bean,可以指定Bean的作用域、生命周期等。
@Configuration public class AppConfig { @Bean public MyBean myBean() { return new MyBean(); } }@Value
- 注入外部配置的值,可以用于字段、构造器、设置方法。
import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class MyComponent { @Value("${my.property}") private String myProperty; // ... }@PathVariable
- 从 URL 中提取变量值,可以指定参数是否必须。
@GetMapping("/users/{id}") public User getUserById(@PathVariable Long id) { // ... }@RequestParam
- 从请求参数中提取值。
@GetMapping("/users") public List<User> getUsersByStatus(@RequestParam String status) { // ... }@RequestBody
- 将 HTTP 请求体绑定到方法参数。
@PostMapping("/users") public User createUser(@RequestBody User user) { // ... }@ResponseBody
- 将方法返回值写入 HTTP 响应体。
@Controller public class MyController { @ResponseBody @GetMapping("/hello") public String hello() { return "Hello, World!"; } }@EnableAutoConfiguration
- 根据添加的 jar 依赖自动配置项目。
@SpringBootApplication // 包含 @EnableAutoConfiguration public class MyApp { public static void main(String[] args) { SpringApplication.run(MyApp.class, args); } }@Profile
- 指定某些 Bean 只在特定的环境下创建。
@Configuration @Profile("dev") public class DevConfig { // ... }@Lazy
- 延迟加载 Bean。
@Service public class MyService { private final MyDependency myDependency; @Autowired public MyService(@Lazy MyDependency myDependency) { this.myDependency = myDependency; } // ... }@Transactional
- 声明事务管理。
import org.springframework.transaction.annotation.Transactional; @Service public class MyService { @Transactional public void doSomething() { // ... } }@Cacheable
- 声明缓存方法的结果。
import org.springframework.cache.annotation.Cacheable; @Service public class MyService { @Cacheable("users") public User findUser(String user) { // ... } }
Spring Boot 自动配置原理:@Conditional 条件注解族
Spring Boot 的"魔法"很大一部分来自 @Conditional 条件注解。它们让 Spring 只在满足特定条件时才创建 Bean,这是自动配置的核心机制。
| 注解 | 条件 | 典型应用场景 |
|---|---|---|
@ConditionalOnClass | 类路径存在指定类 | 检测到 MySQL 驱动才创建 DataSource |
@ConditionalOnMissingClass | 类路径不存在指定类 | 避免与第三方库冲突 |
@ConditionalOnBean | 容器中存在指定 Bean | AOP 代理只在目标 Bean 存在时启用 |
@ConditionalOnMissingBean | 容器中不存在指定 Bean | 用户自定义 Bean 覆盖默认配置 |
@ConditionalOnProperty | 指定属性匹配值 | spring.cache.type=[redis](/posts/redis/) 才启用 RedisCache |
@ConditionalOnWebApplication | 是 Web 应用 | 只在 Web 环境注册 Filter |
// 自定义自动配置:仅在类路径存在 Redis 且用户未自定义时创建
@Configuration
@ConditionalOnClass(RedisOperations.class)
@ConditionalOnMissingBean(RedisTemplate.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {
@Bean
@ConditionalOnProperty(name = "spring.redis.enabled", havingValue = "true", matchIfMissing = true)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
return template;
}
}
调试技巧:启动时添加
--debug参数或在application.properties中设置debug=true,Spring Boot 会输出完整的自动配置报告,显示哪些配置类被匹配、哪些被排除及原因。
AOP 切面编程:声明式横切关注点
Spring AOP 通过代理模式实现,允许在不修改业务代码的情况下,统一处理日志、权限、事务、缓存等横切关注点。
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
@Component
public class LoggingAspect {
// 定义切点:匹配 Service 层所有方法
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}
// 前置通知:方法执行前记录入参
@Before("serviceLayer()")
public void logBefore(JoinPoint joinPoint) {
String method = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("[BEFORE] " + method + " called with args: " + Arrays.toString(args));
}
// 后置通知:方法返回后记录结果
@AfterReturning(pointcut = "serviceLayer()", returning = "result")
public void logAfter(JoinPoint joinPoint, Object result) {
System.out.println("[AFTER] " + joinPoint.getSignature().getName() + " returned: " + result);
}
// 环绕通知:计算方法执行时间
@Around("serviceLayer()")
public Object measureExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed(); // 执行目标方法
long elapsed = System.currentTimeMillis() - start;
System.out.println("[PERF] " + pjp.getSignature().getName() + " took " + elapsed + "ms");
return result;
}
// 异常通知:捕获并记录异常
@AfterThrowing(pointcut = "serviceLayer()", throwing = "ex")
public void logException(JoinPoint joinPoint, Throwable ex) {
System.err.println("[ERROR] Exception in " + joinPoint.getSignature().getName() + ": " + ex.getMessage());
}
}
AOP 代理机制:Spring AOP 默认使用 JDK 动态代理(目标类实现接口时)或 CGLIB 代理(目标类无接口时)。同类内部方法调用(this.method())不会触发 AOP,因为绕过了代理对象。解决方案是注入自身代理:
@Service
public class OrderService {
@Autowired
private OrderService self; // 注入代理对象
public void createOrder() {
self.validateStock(); // 通过代理调用,AOP 生效
}
@Transactional
public void validateStock() { /* ... */ }
}
数据访问与事务管理
Spring 的数据访问层通过 @Transactional 实现声明式事务,配合 JPA/Hibernate 完成 ORM 映射。
@Transactional 传播行为
@Service
public class PaymentService {
@Transactional(propagation = Propagation.REQUIRED) // 默认:加入现有事务,无则新建
public void processPayment() { /* ... */ }
@Transactional(propagation = Propagation.REQUIRES_NEW) // 挂起当前事务,新建独立事务
public void auditLog() { /* ... */ }
@Transactional(propagation = Propagation.NESTED) // 嵌套事务,可独立回滚
public void retryOperation() { /* ... */ }
@Transactional(propagation = Propagation.MANDATORY) // 必须在已有事务中调用
public void internalOperation() { /* ... */ }
}
事务失效的常见原因:
- 非 public 方法:Spring AOP 只能代理 public 方法
- 同类内部调用:
this.method()绕过代理 - 异常被捕获:
try-catch吞掉异常,事务无法感知回滚触发条件 - 异步方法:
@Async方法在新线程执行,事务上下文无法传播(需配置TransactionPropagation) - 数据库引擎不支持:MySQL MyISAM 不支持事务,必须用 InnoDB
@Entity 与 JPA 映射
@Entity
@Table(name = "users", indexes = @Index(columnList = "email", unique = true))
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 100)
private String username;
@Column(unique = true)
private String email;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Order> orders = new ArrayList<>();
@CreationTimestamp
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
}
Spring Security:方法级安全控制
Spring Security 不仅提供 URL 级别的访问控制,还通过注解实现细粒度的方法级权限管理。
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 启用 @PreAuthorize、@PostAuthorize、@Secured
}
@Service
public class OrderService {
// 只有 ADMIN 或订单所有者才能查看
@PreAuthorize("hasRole('ADMIN') or #orderId == authentication.principal.id")
public Order getOrder(Long orderId) { /* ... */ }
// 返回后校验:确保用户只能看到自己的数据
@PostAuthorize("returnObject.userId == authentication.principal.id")
public Order getOrderById(Long orderId) { /* ... */ }
// 只接受特定角色
@Secured("ROLE_MANAGER")
public void refundOrder(Long orderId) { /* ... */ }
// 批量操作前过滤:只处理当前用户有权限的数据
@PreFilter("filterObject.userId == authentication.principal.id")
public void batchUpdate(List<Order> orders) { /* ... */ }
}
SpEL 表达式:
@PreAuthorize支持 Spring Expression Language,可以引用方法参数(#orderId)、当前认证对象(authentication)、甚至是 Bean 的方法(@myBean.check(#id))。
异步与定时任务
Spring 的 @Async 和 @Scheduled 注解让异步编程和定时任务变得简单,但需要注意线程池配置和异常处理。
@EnableAsync
@EnableScheduling
@SpringBootApplication
public class MyApp { /* ... */ }
@Service
public class NotificationService {
// 异步发送邮件,不阻塞主线程
@Async("emailTaskExecutor") // 指定自定义线程池
public CompletableFuture<String> sendEmail(String to, String subject, String body) {
// 模拟发送耗时 2 秒
try { Thread.sleep(2000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
return CompletableFuture.completedFuture("Email sent to " + to);
}
// 每 5 分钟执行一次数据清理
@Scheduled(cron = "0 */5 * * * *")
public void cleanupExpiredData() {
System.out.println("Running cleanup at " + LocalDateTime.now());
}
// 应用启动后延迟 10 秒执行,之后每 30 秒执行
@Scheduled(initialDelay = 10000, fixedRate = 30000)
public void healthCheck() { /* ... */ }
}
// 自定义线程池配置
@Configuration
public class AsyncConfig {
@Bean("emailTaskExecutor")
public Executor emailTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("email-");
executor.initialize();
return executor;
}
}
@Async 失效的常见原因:
- 调用方和
@Async方法在同一个类中(必须通过代理调用) - 方法为 private 或 static
- 返回值不是
void、Future或CompletableFuture - 未添加
@EnableAsync
配置与属性绑定最佳实践
// application.yml
// app:
// mail:
// host: smtp.example.com
// port: 587
// username: noreply@example.com
@ConfigurationProperties(prefix = "app.mail")
@Component
@Data // Lombok
public class MailProperties {
@NotBlank
private String host;
@Min(1)
@Max(65535)
private int port;
@Email
private String username;
@Pattern(regexp = "^(plain|ssl|tls)$")
private String security = "tls";
}
// 使用 JSR-303 注解校验配置属性
@Validated
@ConfigurationProperties(prefix = "app.mail")
public class MailProperties { /* ... */ }
延伸阅读
- Java 快速入门教程 — Java 核心概念与语法速查
- Java 企业级消息队列集成 — Spring AMQP / Kafka 集成
- Java Web 安全 — Spring Security 深度实践
- 微服务服务发现 — Spring Cloud Eureka / Consul
这些注解和代码示例应该能帮助你更好地理解和使用 Spring Boot 中的注解。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。