04.Spring 框架注解体系详解
Spring 框架注解体系详解
本文详细介绍 Spring、Spring Boot 及 Spring Cloud 中常用注解的用途、生命周期及使用方式,帮助开发者更深入理解 Spring 注解驱动编程模式。
参考来源:Spring、SpringMVC、SpringBoot、SpringCloud 框架常用注解说明
目录
- 注解基础知识
- 什么是注解
- 注解的定义方式
- 注解的生命周期
- Spring 核心注解
- @Bean vs 其他注解
- 配置类相关注解
- 组件注册相关注解
- 依赖注入相关注解
- Bean 的生命周期
- 生命周期概述
- 初始化和销毁方法
- Bean 后处理器
- 完整生命周期流程
- Spring MVC 注解
- 控制器相关注解
- 请求映射相关注解
- 请求参数相关注解
- Spring Boot 注解
- 自动配置相关注解
- 属性配置相关注解
- Spring Cloud 注解
- 服务注册与发现注解
- 断路器相关注解
- 配置中心相关注解
注解基础知识
什么是注解
注解(Annotation)是 Java 5 引入的一种特殊类型的接口,它是一种元数据,用于提供有关程序的数据,但不属于程序本身。注解对于它所修饰的代码没有直接影响,但可以被工具或框架读取,用于生成代码、编译检查或在运行时通过反射处理。
Spring 框架大量使用注解来简化配置,提高开发效率,实现声明式编程。
注解的定义方式
在 Java 中,注解通过@interface
关键字定义:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation {String value() default "";int count() default 0;
}
其中:
@Target
:指定注解可以应用的元素类型(类、方法、字段等)@Retention
:指定注解的保留策略(源码、编译时、运行时)@Documented
:表示注解应该被文档工具记录- 注解可以定义属性(如
value()
和count()
)以及它们的默认值
注解的生命周期
注解的生命周期由@Retention
决定:
- SOURCE:注解仅在源码中保留,编译时被丢弃
- CLASS:注解在编译时被保留在类文件中,但不会被 VM 加载(默认行为)
- RUNTIME:注解在运行时可以通过反射 API 获取
Spring 框架中的注解通常都使用RUNTIME
级别,这样才能在应用运行时通过反射机制读取注解信息并做相应处理。
Spring 核心注解
@Bean vs 其他注解
@Bean
是 Spring 最基础的注解之一,它与其他组件注解(如@Component
、@Service
等)有以下区别:
-
定义方式不同:
@Bean
用于方法级别,标注在方法上@Component
等注解用于类级别,标注在类上
-
使用场景不同:
@Bean
通常用于注册第三方库中的类实例或需要复杂初始化的 Bean@Component
等用于将自己编写的类注册为 Spring Bean
-
配置灵活性:
@Bean
允许通过方法体进行复杂逻辑处理和初始化@Component
等注解配置相对简单,主要依靠其他注解配合使用
示例对比:
// 使用@Bean注解
@Configuration
public class AppConfig {@Beanpublic MyService myService() {MyService service = new MyService();service.setProperty("someValue");return service;}
}// 使用@Component注解
@Component
public class MyService {private String property;public void setProperty(String property) {this.property = property;}
}
配置类相关注解
@Configuration
标记一个类作为 Bean 定义的源,等同于 XML 配置中的<beans>
标签。
生命周期:在应用上下文初始化时处理,Spring 会创建该类的 CGLIB 代理以确保@Bean 方法的内部调用也会通过容器。
@Configuration
public class AppConfig {@Beanpublic DataSource dataSource() {return new DriverManagerDataSource("jdbc:mysql://localhost:3306/mydb");}@Beanpublic JdbcTemplate jdbcTemplate() {// 内部调用dataSource()会返回容器中的单例return new JdbcTemplate(dataSource());}
}
@ComponentScan
指定要扫描的包,寻找带有@Component
及其派生注解的类,自动将它们注册为 Bean。
@Configuration
@ComponentScan(basePackages = "com.example.app")
public class AppConfig {// 配置代码
}
或者使用类型安全的方式:
@Configuration
@ComponentScan(basePackageClasses = {UserRepository.class, ProductService.class})
public class AppConfig {// 配置代码
}
@Import
用于导入其他配置类。
@Configuration
@Import({DatabaseConfig.class, SecurityConfig.class})
public class AppConfig {// 应用主配置
}
@PropertySource
加载外部属性文件。
@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig {@Autowiredprivate Environment env;@Beanpublic DataSource dataSource() {String url = env.getProperty("jdbc.url");String username = env.getProperty("jdbc.username");String password = env.getProperty("jdbc.password");return new DriverManagerDataSource(url, username, password);}
}
组件注册相关注解
@Component
基础组件注解,表示该类是一个 Spring 组件,会自动注册到 Spring 容器中。
@Component
public class MyComponent {// 组件实现
}
@Repository
标记数据访问层的类,是@Component
的特化。Spring 会为这些类提供持久化异常转换功能。
@Repository
public class UserRepository {public User findById(Long id) {// 数据访问逻辑return user;}
}
@Service
标记业务逻辑层的类,是@Component
的特化,主要用于业务服务的实现类。
@Service
public class UserService {@Autowiredprivate UserRepository userRepository;public User getUserById(Long id) {return userRepository.findById(id);}
}
@Controller / @RestController
标记表现层的类,用于处理 Web 请求。
@Controller
返回视图@RestController
等同于@Controller + @ResponseBody
,直接返回数据
@Controller
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/users/{id}")public String getUser(@PathVariable Long id, Model model) {model.addAttribute("user", userService.getUserById(id));return "userDetails"; // 返回视图名}
}@RestController
public class UserApiController {@Autowiredprivate UserService userService;@GetMapping("/api/users/{id}")public User getUser(@PathVariable Long id) {return userService.getUserById(id); // 直接返回对象,自动转为JSON}
}
依赖注入相关注解
@Autowired
自动装配依赖,可用于构造函数、字段、方法参数等。
@Service
public class UserService {private final UserRepository userRepository;// 构造器注入(推荐)@Autowiredpublic UserService(UserRepository userRepository) {this.userRepository = userRepository;}// 字段注入@Autowiredprivate EmailService emailService;// 方法注入@Autowiredpublic void setLogger(Logger logger) {this.logger = logger;}
}
@Qualifier
当有多个相同类型的 Bean 时,指定要注入的具体 Bean。
@Service
public class NotificationService {private final MessageSender messageSender;@Autowiredpublic NotificationService(@Qualifier("emailSender") MessageSender messageSender) {this.messageSender = messageSender;}
}@Component("emailSender")
public class EmailSender implements MessageSender {// 实现
}@Component("smsSender")
public class SmsSender implements MessageSender {// 实现
}
@Value
注入外部配置的属性值或表达式结果。
@Component
public class AppSettings {// 从配置文件注入@Value("${app.name}")private String appName;// 默认值@Value("${app.timeout:30}")private int timeout;// SpEL表达式@Value("#{systemProperties['user.region']}")private String region;
}
@Primary
当有多个相同类型的 Bean 时,指定默认的首选 Bean。
@Component
@Primary
public class PrimaryDataSource implements DataSource {// 实现
}@Component
public class SecondaryDataSource implements DataSource {// 实现
}
Bean 的生命周期
生命周期概述
Bean 的生命周期是指 Bean 从创建、初始化到销毁的整个过程。在 Spring 中,Bean 的生命周期由 IoC 容器管理,主要分为四个阶段:
- 实例化(Instantiation):创建 Bean 的实例
- 属性赋值(Populate):为 Bean 的属性设置值和对其他 Bean 的引用
- 初始化(Initialization):调用 Bean 的初始化方法
- 销毁(Destruction):在容器关闭时,调用 Bean 的销毁方法
需要注意的是,对于**单例(Singleton)Bean,实例化和初始化是在容器启动时完成的,销毁是在容器关闭时执行的;而对于原型(Prototype)**Bean,实例化和初始化是在每次获取 Bean 时执行的,但 Spring 不会管理原型 Bean 的销毁过程。
初始化和销毁方法
Spring 提供了多种方式定义 Bean 的初始化和销毁方法:
1. init-method
和destroy-method
属性
在使用@Bean
注解时,可以通过initMethod
和destroyMethod
属性指定初始化和销毁方法:
@Configuration
public class AppConfig {@Bean(initMethod = "init", destroyMethod = "cleanup")public DatabaseClient databaseClient() {DatabaseClient client = new DatabaseClient();client.setUrl("jdbc:mysql://localhost:3306/mydb");return client;}
}public class DatabaseClient {private String url;public void setUrl(String url) {this.url = url;}// 初始化方法public void init() {System.out.println("DatabaseClient initializing with URL: " + url);// 连接数据库等初始化操作}// 销毁方法public void cleanup() {System.out.println("DatabaseClient cleaning up resources");// 关闭连接等清理操作}
}
2. InitializingBean
和DisposableBean
接口
Bean 可以实现这两个接口,分别提供初始化和销毁的回调方法:
@Component
public class CacheManager implements InitializingBean, DisposableBean {private Map<String, Object> cache;@Overridepublic void afterPropertiesSet() throws Exception {// 在所有属性设置完成后调用this.cache = new ConcurrentHashMap<>();System.out.println("CacheManager initialized");}@Overridepublic void destroy() throws Exception {// 在容器销毁Bean之前调用this.cache.clear();System.out.println("CacheManager destroyed");}
}
3. @PostConstruct
和@PreDestroy
注解
这是 JSR-250 规范定义的注解,可以标记在 Bean 的方法上:
@Component
public class UserService {private DatabaseClient dbClient;@Autowiredpublic void setDbClient(DatabaseClient dbClient) {this.dbClient = dbClient;}@PostConstructpublic void initialize() {// 在依赖注入完成后调用System.out.println("UserService is initialized");}@PreDestroypublic void cleanup() {// 在容器销毁Bean之前调用System.out.println("UserService is cleaning up");}
}
各种初始化方法的调用顺序(从先到后):
@PostConstruct
注解标记的方法InitializingBean
接口的afterPropertiesSet()
方法@Bean(initMethod="...")
指定的初始化方法
各种销毁方法的调用顺序(从先到后):
@PreDestroy
注解标记的方法DisposableBean
接口的destroy()
方法@Bean(destroyMethod="...")
指定的销毁方法
Bean 后处理器
BeanPostProcessor
是 Spring 框架中非常重要的扩展点,它允许在 Bean 初始化前后进行自定义处理:
public interface BeanPostProcessor {// 初始化前的处理default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}// 初始化后的处理default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}
实现BeanPostProcessor
接口的例子:
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof AuditableBean) {System.out.println("Before initialization of bean: " + beanName);((AuditableBean) bean).setCreatedDate(new Date());}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof TransactionalBean) {System.out.println("After initialization of bean: " + beanName);// 可以返回原始Bean的代理对象,例如添加事务处理return createProxy(bean);}return bean;}private Object createProxy(Object bean) {// 创建代理对象的逻辑return bean; // 简化示例}
}
Spring 框架内部使用大量的BeanPostProcessor
实现来处理各种功能,例如:
AutowiredAnnotationBeanPostProcessor
:处理@Autowired
注解CommonAnnotationBeanPostProcessor
:处理@PostConstruct
、@PreDestroy
等注解ApplicationContextAwareProcessor
:处理各种Aware
接口的回调,如ApplicationContextAware
完整生命周期流程
Spring Bean 的完整生命周期流程如下:
- 实例化前:调用
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
- 实例化:通过构造器或工厂方法创建 Bean 实例
- 实例化后:调用
InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
- 属性赋值前:调用
InstantiationAwareBeanPostProcessor.postProcessPropertyValues()
- 属性赋值:设置 Bean 属性值
- Aware 接口回调:如果 Bean 实现了相关的 Aware 接口(如
BeanNameAware
、BeanFactoryAware
、ApplicationContextAware
等),调用对应的方法 - 初始化前:调用
BeanPostProcessor.postProcessBeforeInitialization()
- 初始化:按顺序调用
@PostConstruct
注解方法、InitializingBean.afterPropertiesSet()
方法、自定义的init-method
- 初始化后:调用
BeanPostProcessor.postProcessAfterInitialization()
- 使用 Bean:Bean 可以在应用中使用了
- 销毁前:如果 Bean 实现了
DestructionAwareBeanPostProcessor
接口,调用postProcessBeforeDestruction()
- 销毁:按顺序调用
@PreDestroy
注解方法、DisposableBean.destroy()
方法、自定义的destroy-method
对于单例 Bean,容器负责管理其完整生命周期;而对于原型 Bean,容器只负责创建,不负责销毁。
示例代码:一个完整展示 Bean 生命周期的示例
@Component
public class LifecycleDemoBean implements InitializingBean, DisposableBean,BeanNameAware, BeanFactoryAware, ApplicationContextAware {private String beanName;public LifecycleDemoBean() {System.out.println("1. Constructor: Bean is being created");}@Overridepublic void setBeanName(String name) {this.beanName = name;System.out.println("2. BeanNameAware: Bean name is " + name);}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {System.out.println("3. BeanFactoryAware: Bean factory has been set");}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {System.out.println("4. ApplicationContextAware: Application context has been set");}@PostConstructpublic void postConstruct() {System.out.println("5. @PostConstruct: Post-construct method called");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("6. InitializingBean: Properties have been set");}public void customInit() {System.out.println("7. Custom init method: Initialization completed");}public void doSomething() {System.out.println("8. Bean is in use");}@PreDestroypublic void preDestroy() {System.out.println("9. @PreDestroy: Bean is about to be destroyed");}@Overridepublic void destroy() throws Exception {System.out.println("10. DisposableBean: Bean is being destroyed");}public void customDestroy() {System.out.println("11. Custom destroy method: Bean has been destroyed");}
}@Configuration
public class AppConfig {@Bean(initMethod = "customInit", destroyMethod = "customDestroy")public LifecycleDemoBean lifecycleDemoBean() {return new LifecycleDemoBean();}
}
如果使用上面的配置,并在应用中获取和使用该 Bean,控制台将按顺序打印出所有生命周期阶段的日志。
Spring MVC 注解
控制器相关注解
@Controller
标记类为 Spring MVC 控制器,处理 HTTP 请求。
@Controller
public class HomeController {@GetMapping("/")public String home() {return "home"; // 返回视图名}
}
@RestController
组合注解,等同于@Controller + @ResponseBody
,用于创建 RESTful Web 服务。
@RestController
@RequestMapping("/api")
public class UserApiController {@GetMapping("/users")public List<User> getAllUsers() {// 返回用户列表,自动转换为JSONreturn userService.findAll();}
}
@ControllerAdvice / @RestControllerAdvice
用于定义全局控制器异常处理器、绑定数据或模型属性。
@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(UserNotFoundException.class)public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {ErrorResponse error = new ErrorResponse("USER_NOT_FOUND", ex.getMessage());return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);}
}
请求映射相关注解
@RequestMapping
映射 Web 请求到特定处理器方法。
@Controller
@RequestMapping("/users") // 类级别映射
public class UserController {@RequestMapping(method = RequestMethod.GET) // 方法级别映射public String getAllUsers(Model model) {// 处理GET /usersmodel.addAttribute("users", userService.findAll());return "userList";}@RequestMapping(value = "/{id}", method = RequestMethod.GET)public String getUserById(@PathVariable Long id, Model model) {// 处理GET /users/{id}model.addAttribute("user", userService.findById(id));return "userDetails";}
}
@GetMapping / @PostMapping / @PutMapping / @DeleteMapping / @PatchMapping
@RequestMapping
的特化版本,简化特定 HTTP 方法的请求映射。
@RestController
@RequestMapping("/api/users")
public class UserApiController {@GetMapping // GET /api/userspublic List<User> getAllUsers() {return userService.findAll();}@GetMapping("/{id}") // GET /api/users/{id}public User getUser(@PathVariable Long id) {return userService.findById(id);}@PostMapping // POST /api/userspublic User createUser(@RequestBody User user) {return userService.create(user);}@PutMapping("/{id}") // PUT /api/users/{id}public User updateUser(@PathVariable Long id, @RequestBody User user) {return userService.update(id, user);}@DeleteMapping("/{id}") // DELETE /api/users/{id}public void deleteUser(@PathVariable Long id) {userService.delete(id);}
}
请求参数相关注解
@RequestParam
绑定请求参数到方法参数。
@GetMapping("/search")
public String searchUsers(@RequestParam("query") String query,@RequestParam(value = "page", defaultValue = "1") int page,@RequestParam(value = "size", required = false) Integer size,Model model
) {// 处理 /search?query=john&page=2&size=10List<User> users = userService.search(query, page, size != null ? size : 20);model.addAttribute("users", users);return "searchResults";
}
@PathVariable
绑定 URL 路径变量到方法参数。
@GetMapping("/users/{userId}/posts/{postId}")
public String getPost(@PathVariable("userId") Long userId,@PathVariable Long postId,Model model
) {// 处理 /users/123/posts/456Post post = postService.findByUserAndPostId(userId, postId);model.addAttribute("post", post);return "postDetails";
}
@RequestBody
绑定 HTTP 请求体到方法参数。
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user) {User createdUser = userService.create(user);return new ResponseEntity<>(createdUser, HttpStatus.CREATED);
}
@RequestHeader
绑定请求头到方法参数。
@GetMapping("/greeting")
public String greeting(@RequestHeader("User-Agent") String userAgent,@RequestHeader(value = "Accept-Language", required = false) String language
) {// 根据请求头信息处理return "greeting";
}
Spring Boot 注解
自动配置相关注解
@SpringBootApplication
组合注解,等同于@Configuration + @EnableAutoConfiguration + @ComponentScan
。
@SpringBootApplication
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}
@EnableAutoConfiguration
启用 Spring Boot 的自动配置机制,根据类路径中的依赖自动配置 Spring 应用。
@Configuration
@EnableAutoConfiguration
public class MinimalConfig {// 配置代码
}
@ConditionalOnBean / @ConditionalOnMissingBean
条件注解,根据 Bean 的存在或不存在来决定是否创建特定的 Bean。
@Configuration
public class DatabaseConfig {@Bean@ConditionalOnMissingBeanpublic DataSource dataSource() {// 只有在没有DataSource bean的情况下才会创建return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();}@Bean@ConditionalOnBean(name = "dataSource")public JdbcTemplate jdbcTemplate(DataSource dataSource) {// 只有在存在dataSource bean的情况下才会创建return new JdbcTemplate(dataSource);}
}
@ConditionalOnProperty
根据配置属性的值决定是否创建特定的 Bean。
@Configuration
public class CacheConfig {@Bean@ConditionalOnProperty(name = "app.cache.enabled", havingValue = "true")public CacheManager cacheManager() {// 只有当app.cache.enabled=true时才创建return new ConcurrentMapCacheManager();}
}
属性配置相关注解
@ConfigurationProperties
将外部配置属性绑定到类的字段。
@Component
@ConfigurationProperties(prefix = "app.mail")
public class MailProperties {private String host;private int port;private String username;private String password;private boolean ssl;// getters and setters
}// 在application.properties中:
// app.mail.host=smtp.example.com
// app.mail.port=587
// app.mail.username=user
// app.mail.password=pass
// app.mail.ssl=true
@EnableConfigurationProperties
启用@ConfigurationProperties
注解的类并将其注册为 Spring Bean。
@Configuration
@EnableConfigurationProperties(MailProperties.class)
public class MailConfig {@Beanpublic JavaMailSender mailSender(MailProperties properties) {JavaMailSenderImpl sender = new JavaMailSenderImpl();sender.setHost(properties.getHost());sender.setPort(properties.getPort());sender.setUsername(properties.getUsername());sender.setPassword(properties.getPassword());return sender;}
}
Spring Cloud 注解
服务注册与发现注解
@EnableEurekaServer
启用 Eureka 服务器,用于服务注册和发现。
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication.class, args);}
}
@EnableDiscoveryClient / @EnableEurekaClient
启用服务发现客户端功能,将应用注册到注册中心。
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {public static void main(String[] args) {SpringApplication.run(UserServiceApplication.class, args);}
}
断路器相关注解
@EnableCircuitBreaker
启用断路器模式,当依赖服务失败时提供回退机制。
@SpringBootApplication
@EnableCircuitBreaker
public class PaymentServiceApplication {public static void main(String[] args) {SpringApplication.run(PaymentServiceApplication.class, args);}
}
@HystrixCommand
标记可能失败的方法,提供回退策略。
@Service
public class UserService {@Autowiredprivate RestTemplate restTemplate;@HystrixCommand(fallbackMethod = "getDefaultUser")public User getUserById(Long id) {return restTemplate.getForObject("http://user-service/users/" + id, User.class);}public User getDefaultUser(Long id) {// 回退方法,当getUserById方法失败时调用return new User(id, "Default User", "default@example.com");}
}
配置中心相关注解
@EnableConfigServer
启用 Spring Cloud Config 服务器,集中管理分布式系统的配置。
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {public static void main(String[] args) {SpringApplication.run(ConfigServerApplication.class, args);}
}
@RefreshScope
标记需要在配置更改时重新创建的 Bean。
@RestController
@RefreshScope
public class ConfigController {@Value("${greeting.message}")private String message;@GetMapping("/greeting")public String getGreeting() {return message;}
}
注解的工作原理
Spring 注解的工作原理基于 Java 反射机制和 Spring 的BeanPostProcessor
机制:
- 扫描阶段:Spring 容器启动时,会扫描类路径下的类,查找带有特定注解的类
- 解析阶段:识别这些注解并解析其元数据
- 注册阶段:根据注解信息注册 Bean 定义
- 后处理阶段:通过各种
BeanPostProcessor
实现对 Bean 进行增强,如依赖注入 - 初始化阶段:按照生命周期回调初始化 Bean
以@Autowired
为例,其工作流程如下:
- Spring 通过
AutowiredAnnotationBeanPostProcessor
处理带有@Autowired
注解的字段或方法 - 在 Bean 创建后、初始化前,该处理器查找所有带
@Autowired
注解的注入点 - 对每个注入点,从容器中查找匹配的 Bean
- 如果找到唯一匹配,则注入该 Bean;如果找到多个匹配,则查找
@Primary
或使用@Qualifier
进行筛选 - 如果未找到匹配且
required=true
(默认),则抛出异常;如果required=false
,则不进行注入
最佳实践
-
选择合适的注入方式
- 优先使用构造器注入,特别是对于必需的依赖
- 避免过度使用字段注入,这会使测试变得困难
-
合理使用组件扫描
- 明确指定要扫描的包,避免扫描范围过大
- 对于复杂项目,考虑使用多个配置类分组管理 Bean
-
善用条件注解
- 使用条件注解创建更灵活的配置
- 利用 profiles 处理不同环境的配置
-
遵循单一职责原则
- 每个 Bean 应该有明确的职责
- 避免创建过于复杂的配置类
-
注意 Bean 的作用域
- 默认情况下 Bean 是单例的,注意并发问题
- 对于有状态的 Bean,考虑使用
prototype
、request
或session
作用域