🏷️ 第5章 SpringBoot 注解

掌握SpringBoot核心注解 - 从基础到高级应用

学习进度:5/18 章节 (27.5%)

💻 查看完整代码 - 在线IDE体验

🎯 本章学习目标

  • 理解SpringBoot注解的作用机制
  • 掌握核心启动注解的使用
  • 学会Web开发相关注解
  • 了解数据访问注解
  • 掌握配置和依赖注入注解

⏰ 预计学习时间

2小时(理论学习 + 代码实践)

📋 注解分类概述

按功能分类:

  • 核心注解:@SpringBootApplication、@Configuration等
  • Web注解:@Controller、@RestController、@RequestMapping等
  • 数据注解:@Entity、@Repository、@Transactional等
  • 依赖注入:@Autowired、@Component、@Service等
  • 配置注解:@Value、@ConfigurationProperties等

💡 学习建议

注解是SpringBoot的核心特性,建议结合实际代码理解每个注解的作用和使用场景

🚀 核心启动注解

@SpringBootApplication
SpringBoot应用的主注解,组合了多个核心注解
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

等价于:@Configuration + @EnableAutoConfiguration + @ComponentScan

@Configuration
标识配置类,替代传统的XML配置文件
@Configuration public class AppConfig { @Bean public DataSource dataSource() { return new HikariDataSource(); } }
@EnableAutoConfiguration
启用SpringBoot的自动配置机制
@EnableAutoConfiguration @ComponentScan public class Application { // 自动配置数据源、JPA等 }
@ComponentScan
指定组件扫描的包路径
@ComponentScan(basePackages = { "com.example.controller", "com.example.service" }) public class Application { }
// 完整的主启动类示例 package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }

🌐 Web开发注解

@RestController
RESTful API控制器,自动将返回值序列化为JSON
@RestController @RequestMapping("/api/users") public class UserController { @GetMapping("/{id}") public User getUser(@PathVariable Long id) { return userService.findById(id); } }
@Controller
传统MVC控制器,通常返回视图名称
@Controller public class HomeController { @GetMapping("/") public String home(Model model) { model.addAttribute("message", "Hello"); return "index"; // 返回视图名 } }
@RequestMapping
映射HTTP请求到处理方法
@RequestMapping( value = "/users", method = RequestMethod.GET, produces = "application/json" ) public List<User> getUsers() { return userService.findAll(); }
@GetMapping / @PostMapping
HTTP方法特定的映射注解
@GetMapping("/users/{id}") public User getUser(@PathVariable Long id) {} @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) {}
@PathVariable
绑定URL路径中的变量
@GetMapping("/users/{id}/orders/{orderId}") public Order getUserOrder( @PathVariable Long id, @PathVariable Long orderId ) { return orderService.findByUserAndId(id, orderId); }
@RequestParam
绑定请求参数
@GetMapping("/users") public List<User> getUsers( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size, @RequestParam(required = false) String name ) { return userService.findUsers(page, size, name); }
@RequestBody
绑定请求体中的JSON数据
@PostMapping("/users") public User createUser(@RequestBody User user) { return userService.save(user); } @PostMapping("/users/batch") public List<User> createUsers( @RequestBody List<User> users ) { return userService.saveAll(users); }
@ResponseBody
将返回值直接写入HTTP响应体
@Controller public class ApiController { @GetMapping("/api/data") @ResponseBody public Map<String, Object> getData() { Map<String, Object> result = new HashMap<>(); result.put("status", "success"); return result; } }
// 完整的RESTful控制器示例 @RestController @RequestMapping("/api/users") @CrossOrigin(origins = "*") public class UserController { @Autowired private UserService userService; @GetMapping public ResponseEntity<List<User>> getAllUsers( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size ) { Page<User> users = userService.findAll(PageRequest.of(page, size)); return ResponseEntity.ok(users.getContent()); } @GetMapping("/{id}") public ResponseEntity<User> getUser(@PathVariable Long id) { User user = userService.findById(id); return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build(); } @PostMapping public ResponseEntity<User> createUser(@RequestBody @Valid User user) { User savedUser = userService.save(user); return ResponseEntity.status(HttpStatus.CREATED).body(savedUser); } @PutMapping("/{id}") public ResponseEntity<User> updateUser( @PathVariable Long id, @RequestBody @Valid User user ) { User updatedUser = userService.update(id, user); return ResponseEntity.ok(updatedUser); } @DeleteMapping("/{id}") public ResponseEntity<Void> deleteUser(@PathVariable Long id) { userService.deleteById(id); return ResponseEntity.noContent().build(); } }

💉 依赖注入注解

@Component
通用组件注解,标识Spring管理的Bean
@Component public class EmailService { public void sendEmail(String to, String subject) { // 发送邮件逻辑 } }
@Service
业务逻辑层组件,@Component的特化
@Service @Transactional public class UserService { @Autowired private UserRepository userRepository; public User save(User user) { return userRepository.save(user); } }
@Repository
数据访问层组件,提供异常转换
@Repository public class UserRepositoryImpl { @PersistenceContext private EntityManager entityManager; public List<User> findByCustomQuery() { return entityManager .createQuery("SELECT u FROM User u") .getResultList(); } }
@Autowired
自动装配依赖,可用于字段、方法、构造器
@Service public class OrderService { // 字段注入 @Autowired private UserService userService; // 构造器注入(推荐) private final PaymentService paymentService; @Autowired public OrderService(PaymentService paymentService) { this.paymentService = paymentService; } // 方法注入 @Autowired public void setEmailService(EmailService emailService) { this.emailService = emailService; } }
@Qualifier
指定要注入的Bean名称
@Service public class NotificationService { @Autowired @Qualifier("emailNotifier") private Notifier emailNotifier; @Autowired @Qualifier("smsNotifier") private Notifier smsNotifier; }
@Primary
标识主要的Bean,当有多个候选时优先选择
@Component @Primary public class EmailNotifier implements Notifier { // 默认的通知实现 } @Component public class SmsNotifier implements Notifier { // 短信通知实现 }

⚠️ 依赖注入最佳实践

  • 优先使用构造器注入,避免字段注入
  • 使用@Qualifier解决多个Bean的歧义
  • 合理使用@Primary标识默认实现
  • 避免循环依赖

⚙️ 配置注解

@Value
注入配置文件中的属性值
@Component public class AppConfig { @Value("${app.name}") private String appName; @Value("${server.port:8080}") private int serverPort; @Value("#{systemProperties['java.home']}") private String javaHome; }
@ConfigurationProperties
批量绑定配置属性到Java对象
@ConfigurationProperties(prefix = "app.database") @Component public class DatabaseConfig { private String url; private String username; private String password; private int maxConnections; // getter和setter方法 }
@Profile
指定Bean在特定环境下才生效
@Configuration @Profile("development") public class DevConfig { @Bean public DataSource dataSource() { return new H2DataSource(); } } @Configuration @Profile("production") public class ProdConfig { @Bean public DataSource dataSource() { return new MySQLDataSource(); } }
@Conditional
条件化配置,满足条件时才创建Bean
@Configuration public class ConditionalConfig { @Bean @ConditionalOnProperty( name = "feature.cache.enabled", havingValue = "true" ) public CacheManager cacheManager() { return new RedisCacheManager(); } @Bean @ConditionalOnMissingBean public CacheManager defaultCacheManager() { return new SimpleCacheManager(); } }
// 配置属性类示例 @ConfigurationProperties(prefix = "app") @Component @Validated public class AppProperties { @NotBlank private String name; @Min(1) @Max(65535) private int port = 8080; private Database database = new Database(); private List<String> allowedOrigins = new ArrayList<>(); // getter和setter方法 public static class Database { private String url; private String username; private String password; private int maxConnections = 10; // getter和setter方法 } }
# application.yml 配置示例 app: name: "My Spring Boot App" port: 8080 database: url: jdbc:mysql://localhost:3306/mydb username: root password: 123456 max-connections: 20 allowed-origins: - http://localhost:3000 - https://example.com

🗄️ 数据访问注解

@Entity
JPA实体类注解
@Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, unique = true) private String username; @Column(nullable = false) private String email; }
@Transactional
声明式事务管理
@Service @Transactional public class UserService { @Transactional(readOnly = true) public User findById(Long id) { return userRepository.findById(id); } @Transactional(rollbackFor = Exception.class) public User save(User user) { return userRepository.save(user); } }
@Query
自定义查询方法
@Repository public interface UserRepository extends JpaRepository<User, Long> { @Query("SELECT u FROM User u WHERE u.email = ?1") User findByEmail(String email); @Query(value = "SELECT * FROM users WHERE age > :age", nativeQuery = true) List<User> findUsersOlderThan(@Param("age") int age); }
@Modifying
标识修改操作的查询方法
@Repository public interface UserRepository extends JpaRepository<User, Long> { @Modifying @Query("UPDATE User u SET u.lastLogin = :now WHERE u.id = :id") int updateLastLogin(@Param("id") Long id, @Param("now") LocalDateTime now); @Modifying @Query("DELETE FROM User u WHERE u.active = false") int deleteInactiveUsers(); }

✅ 验证注解

@Valid / @Validated
启用Bean验证
@PostMapping("/users") public User createUser(@RequestBody @Valid User user) { return userService.save(user); } @Service @Validated public class UserService { public User save(@Valid User user) { return userRepository.save(user); } }
常用验证注解
Bean Validation标准注解
@Entity public class User { @NotNull(message = "用户名不能为空") @Size(min = 3, max = 20, message = "用户名长度3-20字符") private String username; @Email(message = "邮箱格式不正确") @NotBlank(message = "邮箱不能为空") private String email; @Min(value = 18, message = "年龄不能小于18") @Max(value = 100, message = "年龄不能大于100") private Integer age; @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确") private String phone; }

❗ 常见问题解决

问题1:@Autowired注入失败

原因:Bean未被Spring管理或包扫描路径不正确

解决:检查@Component注解和@ComponentScan配置

问题2:循环依赖

原因:两个Bean相互依赖

解决:使用@Lazy注解或重构代码结构

问题3:@Value注入null

原因:配置文件中没有对应属性或格式错误

解决:检查配置文件和属性名称

💡 调试技巧

  • 使用@PostConstruct验证Bean初始化
  • 启用debug日志查看Bean创建过程
  • 使用ApplicationContext.getBean()手动获取Bean
  • 检查@Profile和@Conditional条件

🎯 最佳实践

注解使用原则:

  • 优先使用构造器注入
  • 合理使用@Profile区分环境
  • 使用@ConfigurationProperties替代多个@Value
  • 在Service层使用@Transactional

性能优化建议:

  • 避免过度使用@Autowired
  • 合理设置@Transactional的传播行为
  • 使用@Lazy延迟加载非必需Bean
  • 正确配置@ComponentScan范围

🏆 核心要点

SpringBoot注解是声明式编程的体现,理解每个注解的作用机制是掌握SpringBoot的关键

🎉 恭喜完成第5章学习!

你已经掌握了SpringBoot的核心注解,接下来让我们学习SpringBoot的配置文件。

📚 进入第6章:SpringBoot 配置文件 ⬅️ 返回第4章 🏠 返回课程首页