Spring Boot常用注解说明

Spring Boot 是一个基于 Spring 框架的项目,它通过简化配置来帮助开发者快速构建微服务和其他应用程序。在 Spring Boot 中,注解(Annotations)扮演着非常重要的角色,它们用于减少配置和提高代码的可读性。以下是一些常用的 Spring Boot 注解及其详解: 1.

Spring Boot 是一个基于 Spring 框架的项目,它通过简化配置来帮助开发者快速构建微服务和其他应用程序。在 Spring Boot 中,注解(Annotations)扮演着非常重要的角色,它们用于减少配置和提高代码的可读性。以下是一些常用的 Spring Boot 注解及其详解:

  1. @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);
        }
    }
    
  2. @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!";
        }
    }
    
  3. @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";
        }
    }
    
  4. @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) {
        // ...
    }
    
  5. @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;
        }
        // ...
    }
    
  6. @Service

    • 用于标注服务层组件,通常用于业务逻辑处理。
    @Service
    public class UserService {
        // ...
    }
    
  7. @Repository

    • 用于标注数据访问组件,即DAO组件,表明该类用于数据库操作。
    import org.springframework.stereotype.Repository;
    
    @Repository
    public interface UserRepository extends JpaRepository<User, Long> {
        // ...
    }
    
  8. @Component

    • 用于标注组件,表明该类由 Spring 管理,通常用于非服务层和非数据层的组件。
    @Component
    public class MyComponent {
        // ...
    }
    
  9. @Configuration

    • 用于定义配置类,可以替代传统的XML配置文件,通常用于定义Bean的创建。
    @Configuration
    public class AppConfig {
        @Bean
        public MyBean myBean() {
            return new MyBean();
        }
    }
    
  10. @Bean

    • 在配置类中声明一个 Bean,可以指定Bean的作用域、生命周期等。
    @Configuration
    public class AppConfig {
        @Bean
        public MyBean myBean() {
            return new MyBean();
        }
    }
    
  11. @Value

    • 注入外部配置的值,可以用于字段、构造器、设置方法。
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    @Component
    public class MyComponent {
        @Value("${my.property}")
        private String myProperty;
        // ...
    }
    
  12. @PathVariable

    • 从 URL 中提取变量值,可以指定参数是否必须。
    @GetMapping("/users/{id}")
    public User getUserById(@PathVariable Long id) {
        // ...
    }
    
  13. @RequestParam

    • 从请求参数中提取值。
    @GetMapping("/users")
    public List<User> getUsersByStatus(@RequestParam String status) {
        // ...
    }
    
  14. @RequestBody

    • 将 HTTP 请求体绑定到方法参数。
    @PostMapping("/users")
    public User createUser(@RequestBody User user) {
        // ...
    }
    
  15. @ResponseBody

    • 将方法返回值写入 HTTP 响应体。
    @Controller
    public class MyController {
        @ResponseBody
        @GetMapping("/hello")
        public String hello() {
            return "Hello, World!";
        }
    }
    
  16. @EnableAutoConfiguration

    • 根据添加的 jar 依赖自动配置项目。
    @SpringBootApplication // 包含 @EnableAutoConfiguration
    public class MyApp {
        public static void main(String[] args) {
            SpringApplication.run(MyApp.class, args);
        }
    }
    
  17. @Profile

    • 指定某些 Bean 只在特定的环境下创建。
    @Configuration
    @Profile("dev")
    public class DevConfig {
        // ...
    }
    
  18. @Lazy

    • 延迟加载 Bean。
    @Service
    public class MyService {
        private final MyDependency myDependency;
    
        @Autowired
        public MyService(@Lazy MyDependency myDependency) {
            this.myDependency = myDependency;
        }
        // ...
    }
    
  19. @Transactional

    • 声明事务管理。
    import org.springframework.transaction.annotation.Transactional;
    
    @Service
    public class MyService {
        @Transactional
        public void doSomething() {
            // ...
        }
    }
    
  20. @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容器中存在指定 BeanAOP 代理只在目标 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() { /* ... */ }
}

事务失效的常见原因:

  1. 非 public 方法:Spring AOP 只能代理 public 方法
  2. 同类内部调用:this.method() 绕过代理
  3. 异常被捕获:try-catch 吞掉异常,事务无法感知回滚触发条件
  4. 异步方法:@Async 方法在新线程执行,事务上下文无法传播(需配置 TransactionPropagation)
  5. 数据库引擎不支持: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 失效的常见原因:

  1. 调用方和 @Async 方法在同一个类中(必须通过代理调用)
  2. 方法为 private 或 static
  3. 返回值不是 void、Future 或 CompletableFuture
  4. 未添加 @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 { /* ... */ }

延伸阅读

这些注解和代码示例应该能帮助你更好地理解和使用 Spring Boot 中的注解。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「java」更多文章

  1. 《Spring Boot 入门》18.3 打包与运行
  2. 《Spring Boot 入门》18.2 实现
  3. 《Spring Boot 入门》18.1 需求与设计