开发中反复查的 Spring Boot 注解,一次性整理到位

本文系统梳理 Spring 框架中容器管理和 WebMVC 相关的核心注解,结合使用场景、属性说明和实战示例,帮助开发者深入理解注解的底层逻辑与正确用法。

一、容器相关注解

容器相关注解是 Spring IoC 容器实现 Bean 定义、加载、依赖管理的核心,决定了 Bean 的生命周期、加载条件和依赖关系。

1. @Configuration

@Configuration 是 Spring 3.0 引入的核心注解,用于替代传统 XML 配置文件,标记类为配置类,是 Bean 定义的核心载体。

  • 作用:标注在类上,声明该类为 Spring 配置类,配合@Bean注解定义 Bean;
  • 特性:被标注的类本身也会被注册为 Bean,纳入 Spring 容器管理;
  • 底层逻辑:默认情况下,配置类会被 CGLIB 代理,保证@Bean方法调用时返回容器中已初始化的单例 Bean,而非新创建实例。

属性说明:

属性 说明 补充说明
value Bean 名称 可选,默认使用类名首字母小写作为 Bean 名称
proxyBeanMethods 指定 @Bean 方法是否启用 CGLIB 代理 true(默认):代理模式,调用 @Bean 方法返回容器中的 Bean;② false:轻量模式,调用 @Bean 方法直接 new 新对象,适合无依赖的简单 Bean,提升启动性能

2. @Bean

@Bean 用于在配置类中显式定义 Bean,是 XML 配置中<bean>标签的注解等价实现。

  • 作用:标注在方法上,方法返回值将被注册为 Spring 容器中的 Bean;
  • 作用域:方法必须定义在@Configuration@Component标注的类中;
  • 生命周期:支持指定初始化和销毁方法,对应 XML 中的init-methoddestroy-method

属性说明:

属性 说明 补充说明
value 指定 Bean 名称 name属性等价,优先级相同,支持数组形式定义多个别名
name 指定 Bean 名称 推荐使用,语义更清晰,如name = "userService"
autowireCandidate 是否作为自动装配候选 Bean true(默认):允许被@Autowired自动装配;② false:排除自动装配,仅能通过BeanFactory手动获取
initMethod 初始化方法名 方法需无参、无返回值,Bean 初始化完成后执行,替代InitializingBean接口
destroyMethod 销毁方法名 方法需无参、无返回值,容器关闭时执行(仅单例 Bean 生效),替代DisposableBean接口,默认会检测close()/shutdown()方法

3. @DependsOn

@DependsOn 用于声明 Bean 之间的依赖顺序,确保指定 Bean 在当前 Bean 之前创建。

  • 非强依赖:区别于字段注入 / 构造器注入的 "依赖注入",仅保证创建顺序,不涉及属性赋值;
  • 适用场景:如数据源 Bean 需在数据访问 Bean 之前初始化,或启动时需先加载配置 Bean。

属性说明:

属性 说明
value 依赖的 Bean 名称数组

示例

java 复制代码
@Configuration
public class DependsOnConfig {
   @Bean
   public DataSource dataSource() {
       return new DruidDataSource();
   }
   @Bean
   @DependsOn("dataSource") // 确保 dataSource 先创建
   public JdbcTemplate jdbcTemplate() {
       return new JdbcTemplate(dataSource());
   }
}

4. @ComponentScan

@ComponentScan 用于指定 Spring 扫描 Bean 的包路径,自动注册标注了@Component/@Service/@Repository/@Controller的类。

  • 核心逻辑:通过过滤器(Filter)筛选需要纳入容器的类,支持包含 / 排除规则;
  • 默认行为:未指定包路径时,扫描当前注解所在类的包及其子包。

属性说明:

属性 说明 补充说明
value 扫描的基础包路径 basePackages等价,如value = "com.example.service"
nameGenerator Bean 名称生成器 自定义 Bean 名称规则,需实现BeanNameGenerator接口
scopeResolver Bean 作用域解析器 自定义作用域解析逻辑,需实现ScopeMetadataResolver接口
basePackages 指定扫描的基础包 支持数组形式,如basePackages = {"com.example.service", "com.example.dao"}
basePackageClasses 指定扫描的基准类 扫描指定类所在的包,如basePackageClasses = UserService.class
useDefaultFilters 是否启用默认过滤器 true(默认):扫描@Component及其衍生注解;② false:仅扫描自定义过滤器匹配的类
includeFilters 包含过滤器 仅匹配规则的类被扫描,如指定扫描标注@MyAnnotation的类
excludeFilters 排除过滤器 匹配规则的类不被扫描,如排除@Controller标注的类
lazyInit 是否懒加载扫描到的 Bean true:所有扫描的 Bean 均懒加载;② false(默认):单例 Bean 立即加载

示例

java 复制代码
@Configuration
// 扫描指定包,排除 Controller,仅包含 Service
@ComponentScan(
   basePackages = "com.example",
   excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class),
   includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Service.class)
)
public class ScanConfig {
}

5. @ConditionalOnBean

@ConditionalOnBean 是 Spring Boot 条件注解,仅当容器中存在指定 Bean 时,才加载当前 Bean。

  • 适用场景:按需加载 Bean,如仅当 RedisTemplate 存在时,才创建 Redis 缓存管理器。

属性说明:

属性 说明 补充说明
value 指定 Bean 的 Class 类型 value = RedisTemplate.class
type 指定 Bean 的类型名称 字符串形式,避免类依赖,如type = "org.springframework.data.redis.core.RedisTemplate"
annotation 指定 Bean 需包含的注解 annotation = Repository.class(仅扫描标注 @Repository 的 Bean)
name 指定 Bean 的名称 name = "redisTemplate"
search 是否搜索父容器 / 祖先容器 枚举值:SearchStrategy.CURRENT(仅当前容器,默认)、SearchStrategy.PARENTS(父容器)、SearchStrategy.ALL(所有祖先容器)
parameterizedContainer 指定参数化类型容器 匹配泛型容器中的 Bean,如parameterizedContainer = List.class(匹配 List 类型的 Bean)

示例

java 复制代码
@Configuration
public class ConditionalBeanConfig {
   @Bean
   public RedisTemplate<String, Object> redisTemplate() {
       return new RedisTemplate<>();
   }
   // 仅当 redisTemplate 存在时,创建 RedisCacheManager
   @Bean
   @ConditionalOnBean(name = "redisTemplate")
   public RedisCacheManager cacheManager() {
       return RedisCacheManager.builder(redisTemplate()).build();
   }
}

6. @ConditionalOnMissingBean

@ConditionalOnMissingBean@ConditionalOnBean相反,仅当容器中不存在指定 Bean 时,才加载当前 Bean。

  • 核心用途:实现 "默认 Bean" 逻辑,如自定义 Bean 不存在时,加载框架默认实现。

属性说明:

属性 说明
ignored 忽略匹配的 Class
ignoredType 忽略匹配的类型名称

示例

java 复制代码
@Configuration
public class DefaultBeanConfig {
   // 仅当容器中无 UserService 时,加载默认实现
   @Bean
   @ConditionalOnMissingBean(type = "com.example.service.UserService")
   public UserService defaultUserService() {
       return new DefaultUserService();
   }
}

7. @ConditionalOnClass

@ConditionalOnClass 仅当类路径中存在指定 Class 时,才加载当前 Bean。

  • 适用场景:适配不同依赖环境,如仅当引入 MyBatis 依赖时,加载 MyBatis 配置 Bean。

属性说明:

属性 说明 补充说明
value 指定 Class 类型 value = SqlSessionFactory.class
name 指定 Class 全限定名 避免编译期依赖,如name = "org.apache.ibatis.session.SqlSessionFactory"

示例

java 复制代码
@Configuration
// 仅当类路径存在 SqlSessionFactory 时,加载 MyBatis 配置
@ConditionalOnClass(SqlSessionFactory.class)
public class MyBatisConfig {
   @Bean
   public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
       SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
       factoryBean.setDataSource(dataSource);
       return factoryBean.getObject();
   }
}

8. @ConditionalOnMissingClass

@ConditionalOnMissingClass 仅当类路径中不存在指定 Class 时,才加载当前 Bean。

  • 适用场景:降级处理,如未引入某个依赖时,加载兜底实现。

属性说明:

属性 说明
value 指定 Class 全限定名数组

示例

java 复制代码
@Configuration
// 未引入 Redis 时,加载本地缓存
@ConditionalOnMissingClass("org.springframework.data.redis.core.RedisTemplate")
public class LocalCacheConfig {
   @Bean
   public CacheManager localCacheManager() {
       return new ConcurrentMapCacheManager();
   }
}

9. @ConditionalOnProperty

@ConditionalOnProperty 仅当配置文件中存在指定属性(且值匹配)时,才加载当前 Bean。

  • 核心用途:通过配置开关控制 Bean 加载,实现环境适配。

属性说明:

属性 说明 补充说明
value 属性名数组 name等价,如value = "spring.cache.enabled"
prefix 属性名前缀 简化属性名书写,如prefix = "spring.cache" + name = "enabled" 等价于spring.cache.enabled
name 属性名 支持数组,如name = {"enabled", "type"}
havingValue 指定属性值 匹配属性的具体值,如havingValue = "redis"
matchIfMissing 属性不存在时是否匹配 true:属性不存在时仍加载 Bean;② false(默认):属性不存在则不加载

示例

java 复制代码
@Configuration
// 当 spring.cache.enabled=true 且 type=redis 时,加载 Redis 缓存
@ConditionalOnProperty(
   prefix = "spring.cache",
   name = {"enabled", "type"},
   havingValue = "redis",
   matchIfMissing = false
)
public class RedisCacheConfig {
   // ...
}

10. @ConditionalOnResource

@ConditionalOnResource 仅当类路径中存在指定资源文件时,才加载当前 Bean。

  • 适用场景:加载自定义配置文件,如仅当存在app-custom.properties时,加载对应配置。

属性说明:

属性 说明 补充说明
value 资源路径数组 支持 classpath 路径,如value = "classpath:app-custom.properties"

示例

java 复制代码
@Configuration
// 仅当存在自定义配置文件时,加载配置
@ConditionalOnResource(resources = "classpath:app-custom.properties")
@PropertySource("classpath:app-custom.properties")
public class CustomConfig {
   // ...
}

11. @ConditionalOnSingleCandidate

@ConditionalOnSingleCandidate 仅当容器中指定类型的 Bean仅有一个候选 Bean(或有 @Primary 标记的 Bean)时,才加载当前 Bean。

  • 适用场景:避免多 Bean 冲突,如仅当数据源 Bean 唯一时,加载 JdbcTemplate。

属性说明:

属性 说明
value Bean 的 Class 类型
type Bean 的 Class 全限定名
search 是否搜索父容器

示例

java 复制代码
@Configuration
// 仅当数据源 Bean 唯一时,创建 JdbcTemplate
@ConditionalOnSingleCandidate(DataSource.class)
public class JdbcConfig {
   @Bean
   public JdbcTemplate jdbcTemplate(DataSource dataSource) {
       return new JdbcTemplate(dataSource);
   }
}

12. @Import

@Import 用于手动导入 Bean 到容器,支持三种导入方式,是扩展 Spring 容器的核心注解。

  • 核心优势:无需扫描,直接显式注册 Bean,灵活控制 Bean 加载逻辑。

属性说明:

属性 说明 补充说明
value 导入的 Class 数组 支持三种类型:① 普通配置类(@Configuration 标注);② ImportSelector 实现类(返回 Class 全限定名,批量导入);③ ImportBeanDefinitionRegistrar 实现类(手动注册 BeanDefinition)

示例 1:导入普通配置类

java 复制代码
@Configuration
@Import(MyBatisConfig.class) // 导入 MyBatis 配置类
public class AppMainConfig {
}

示例 2:ImportSelector 实现类

java 复制代码
// 自定义 ImportSelector
public class MyImportSelector implements ImportSelector {
   @Override
   public String[] selectImports(AnnotationMetadata importingClassMetadata) {
       // 批量导入两个 Bean
       return new String[]{"com.example.service.UserService", "com.example.dao.UserDao"};
   }
}
// 导入 Selector
@Configuration
@Import(MyImportSelector.class)
public class SelectorConfig {
}

13. @ImportResource

@ImportResource 用于导入传统 XML 配置文件中的 Bean,实现注解与 XML 配置的兼容。

  • 适用场景:迁移老项目时,保留 XML 配置,逐步过渡到注解配置。

属性说明:

属性 说明 补充说明
value XML 文件路径数组 locations等价,如value = "classpath:spring-dao.xml"
locations XML 文件路径数组 支持多个文件,如locations = {"classpath:spring-service.xml", "classpath:spring-dao.xml"}
reader 自定义 BeanDefinition 读取器 需实现BeanDefinitionReader接口,自定义 XML 解析逻辑

示例

java 复制代码
@Configuration
@ImportResource(locations = "classpath:spring-legacy.xml") // 导入 XML 配置
public class LegacyConfig {
}

14. @Lazy

@Lazy 用于标记 Bean 为懒加载,即仅当首次获取 Bean 时才初始化,

而非容器启动时。

  • 仅对单例 Bean 生效(原型 Bean 默认懒加载);
  • 可标注在@Configuration类上,批量设置该类中@Bean的懒加载。

属性说明:

属性 说明
value 是否懒加载

示例

java 复制代码
@Configuration
public class LazyConfig {
   // 懒加载Bean,首次调用时初始化
   @Bean
   @Lazy(true)
   public HeavyService heavyService() {
       return new HeavyService(); // 初始化耗时较长的Bean
   }
}

15. @Primary

@Primary 标记 Bean 为 "主 Bean",当存在多个同类型 Bean 时,@Autowired优先注入该 Bean。

  • 适用场景:解决多 Bean 自动装配冲突,如默认数据源、默认缓存管理器。

示例

java 复制代码
@Configuration
public class PrimaryConfig {
   @Bean
   @Primary // 主数据源,@Autowired优先注入
   public DataSource primaryDataSource() {
       return new DruidDataSource();
   }
   @Bean
   public DataSource secondaryDataSource() {
       return new HikariDataSource();
   }
}
// 使用时,自动注入primaryDataSource
@Service
public class UserService {
   @Autowired
   private DataSource dataSource; // 注入primaryDataSource
}

16. @Profile

@Profile 用于按环境加载 Bean,仅当指定环境激活时,才加载标注的 Bean。

  • 常用环境:dev(开发)、test(测试)、prod(生产);
  • 激活方式:通过spring.profiles.active配置(如application.yml中设置)。

属性说明:

属性 说明
value 环境名称数组

示例

java 复制代码
@Configuration
public class ProfileConfig {
   // 开发环境数据源
   @Bean
   @Profile("dev")
   public DataSource devDataSource() {
       return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
   }
   // 生产环境数据源
   @Bean
   @Profile("prod")
   public DataSource prodDataSource() {
       return new DruidDataSource();
   }
}

17. @PropertySource

@PropertySource 用于加载自定义配置文件,将配置项纳入 Spring 的 Environment 管理。

  • 核心特性:支持多种编码、忽略不存在的文件,配合@Value@ConfigurationProperties使用。

属性说明:

属性 说明 补充说明
name PropertySource 名称 自定义名称,如name = "customProperties"
value 配置文件路径 value = "classpath:app-custom.properties"
ignoreResourceNotFound 是否忽略不存在的文件 true:忽略;② false(默认):文件不存在则抛异常
encoding 配置文件编码 encoding = "UTF-8"
factory 自定义配置文件读取工厂 需实现PropertySourceFactory,支持 YAML 等非 properties 文件

示例

java 复制代码
@Configuration
@PropertySource(
   value = "classpath:app-custom.properties",
   encoding = "UTF-8",
   ignoreResourceNotFound = true
)
public class PropertyConfig {
   @Value("${app.name}")
   private String appName; // 读取app-custom.properties中的app.name
}

18. @Role

@Role 定义 Bean 的角色,用于区分 Bean 的用途(框架内部 / 应用层)。

  • BeanDefinition.ROLE_APPLICATION(默认):应用层 Bean,开发者关注;
  • BeanDefinition.ROLE_INFRASTRUCTURE:框架内部 Bean,对开发者透明;
  • BeanDefinition.ROLE_SUPPORT:支撑性 Bean,辅助应用层 Bean 运行。

属性说明:

属性 说明
value 角色值

示例

java 复制代码
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE) // 标记为框架内部配置类
public class FrameworkConfig {
   @Bean
   public TransactionManager transactionManager() {
       return new DataSourceTransactionManager();
   }
}

19. @Scope

@Scope 定义 Bean 的作用域,决定 Bean 的生命周期范围。

  • SCOPE_SINGLETON(默认):单例,容器中仅一个实例;
  • SCOPE_PROTOTYPE:原型,每次获取创建新实例;
  • SCOPE_REQUEST:请求作用域,每个 HTTP 请求一个实例;
  • SCOPE_SESSION:会话作用域,每个 HTTP 会话一个实例。

属性说明:

属性 说明 补充说明
value 作用域名称 scopeName等价,如value = ScopeConstants.SCOPE_REQUEST
scopeName 作用域名称 语义更清晰,推荐使用
proxyMode 代理模式 解决作用域依赖问题(如单例 Bean 依赖请求作用域 Bean),可选:① ScopedProxyMode.NO(默认):无代理;② ScopedProxyMode.INTERFACES:JDK 动态代理;③ ScopedProxyMode.TARGET_CLASS:CGLIB 代理

作用域依赖问题: 单例bean依赖请求作用域bean,但是请求作用域bean,只有在请求时才会产生,而单例bean在启动时会进行依赖注入。如果不代理则无法注入请求作用域bean

示例

java 复制代码
@Configuration
public class ScopeConfig {
   // 请求作用域Bean,通过CGLIB代理解决依赖问题
   @Bean
   @Scope(value = ScopeConstants.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
   public RequestContext requestContext() {
       return new RequestContext();
   }
   // 单例Bean依赖请求作用域Bean(通过代理注入)
   @Bean
   public UserService userService() {
       return new UserService(requestContext());
   }
}

20. @AutoConfigureAfter / @AutoConfigureBefore / @AutoConfigureOrder

这三个注解用于控制@Configuration配置类的加载顺序,类似@DependsOn但针对配置类解析阶段。

  • 核心区别:@DependsOn控制 Bean 创建顺序,这三个注解控制配置类解析顺序。

属性说明:

属性 说明
name 配置类全限定名数组
value 配置类 Class 数组

示例

java 复制代码
// 数据源配置先解析
@Configuration
public class DataSourceConfig {
   @Bean
   public DataSource dataSource() {
       return new DruidDataSource();
   }
}
// 事务配置在数据源配置之后解析
@Configuration
@AutoConfigureAfter(DataSourceConfig.class)
public class TransactionConfig {
   @Bean
   public TransactionManager transactionManager(DataSource dataSource) {
       return new DataSourceTransactionManager(dataSource);
   }
}

二、WebMVC 相关注解

WebMVC 注解是 Spring MVC 处理请求、响应、参数绑定、异常处理的核心,专注于 Web 层的请求处理逻辑。

1. @ControllerAdvice

@ControllerAdvice 是 "控制器增强器",全局拦截 Controller 的请求处理流程,配合以下注解使用:

  • @ExceptionHandler:全局异常处理;
  • @InitBinder:全局参数绑定;
  • @ModelAttribute:全局模型属性设置;
  • 扩展能力:实现ResponseBodyAdvice/RequestBodyAdvice,拦截请求 / 响应处理。

属性说明:

属性名 说明 补充说明
basePackages 拦截的基础包路径 仅指定包下的 Controller 被拦截,如basePackages = "com.example.controller"
assignableTypes 拦截的 Controller 父类 / 接口 仅继承指定 Class 的 Controller 被拦截,如assignableTypes = BaseController.class
annotations 拦截的 Controller 注解 仅标注指定注解的 Controller 被拦截,如annotations = RestController.class

示例

java 复制代码
// 全局增强器,拦截所有@RestController标注的控制器
@ControllerAdvice(annotations = RestController.class)
public class GlobalControllerAdvice implements ResponseBodyAdvice<Object>, RequestBodyAdvice {
   // 全局异常处理
   @ExceptionHandler(Exception.class)
   public ResponseEntity<ErrorResponse> handleException(Exception e) {
       ErrorResponse response = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
       return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
   }
   // 全局参数绑定(日期格式)
   @InitBinder
   public void initBinder(WebDataBinder binder) {
       SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
       binder.registerCustomEditor(Date.class, new CustomDateEditor(sdf, true));
   }
   // 全局模型属性
   @ModelAttribute
   public void addGlobalModelAttribute(Model model) {
       model.addAttribute("appName", "SpringMVC Demo");
   }
   // 拦截@ResponseBody响应,自定义处理
   @Override
   public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                 Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                 ServerHttpRequest request, ServerHttpResponse response) {
       // 统一响应格式
       return new Result<>("success", body);
   }
   // 拦截@RequestBody请求,自定义处理
   @Override
   public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
                               Class<?> targetType, Class<? extends HttpMessageConverter<?>> converterType) {
       // 请求参数预处理
       return body;
   }
   // 其他接口实现...
}

2. @ExceptionHandler

@ExceptionHandler 用于处理 Controller 中的异常,可局部(Controller 内)或全局(配合@ControllerAdvice)使用。

  • 核心优势:精准捕获指定异常,统一异常响应格式,避免重复 try-catch。

属性说明:

属性名 说明
value 需处理的异常类型数组

示例(全局异常处理)

java 复制代码
@ControllerAdvice
public class GlobalExceptionHandler {
   private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
   // 处理业务异常
   @ExceptionHandler(BusinessException.class)
   @ResponseBody
   public Result<Void> handleBusinessException(BusinessException e) {
       log.warn("业务异常:{}", e.getMessage());
       return Result.fail(e.getCode(), e.getMessage());
   }
   // 处理参数校验异常
   @ExceptionHandler(MethodArgumentNotValidException.class)
   @ResponseBody
   public Result<Void> handleValidException(MethodArgumentNotValidException e) {
       String message = e.getBindingResult().getFieldError().getDefaultMessage();
       log.warn("参数校验异常:{}", message);
       return Result.fail(400, message);
   }
   // 处理所有未捕获的异常
   @ExceptionHandler(Exception.class)
   @ResponseBody
   @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
   public Result<Void> handleException(Exception e) {
       log.error("系统异常", e);
       return Result.fail(500, "服务器内部错误");
   }
}
// 统一响应结果
class Result<T> {
   private String code;
   private String message;
   private T data;
   // 静态方法:success/fail...
}

3. @InitBinder

@InitBinder 用于自定义 Web 请求参数到 Bean 的绑定规则,解决特殊类型(如日期、枚举)的参数转换问题。

  • 作用域:局部(Controller 内)或全局(配合@ControllerAdvice)。

示例(全局日期参数绑定)

java 复制代码
@ControllerAdvice
public class GlobalInitBinder {
   // 绑定多种日期格式
   @InitBinder
   public void initDateBinder(WebDataBinder binder) {
       // 支持yyyy-MM-dd和yyyy-MM-dd HH:mm:ss两种格式
       CustomDateEditor dateEditor = new CustomDateEditor(new FlexibleDateFormat(), true);
       binder.registerCustomEditor(Date.class, dateEditor);
   }
   // 自定义枚举转换器
   @InitBinder
   public void initEnumBinder(WebDataBinder binder) {
       binder.registerCustomEditor(StatusEnum.class, new EnumEditor(StatusEnum.class));
   }
   // 灵活的日期格式解析器
   static class FlexibleDateFormat extends DateFormat {
       private final List<SimpleDateFormat> formats = Arrays.asList(
           new SimpleDateFormat("yyyy-MM-dd"),
           new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
       );
       @Override
       public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
           return formats.get(0).format(date, toAppendTo, fieldPosition);
       }
       @Override
       public Date parse(String source, ParsePosition pos) {
           for (SimpleDateFormat format : formats) {
               ParsePosition parsePos = new ParsePosition(0);
               Date date = format.parse(source, parsePos);
               if (date != null) {
                   pos.setIndex(parsePos.getIndex());
                   pos.setErrorIndex(parsePos.getErrorIndex());
                   return date;
               }
           }
           return null;
       }
   }
}

4. @ModelAttribute

@ModelAttribute 用于在 Controller 方法执行前,向 Model 中添加通用属性,适用于页面渲染(前后端不分离场景)。

  • 全局使用:配合@ControllerAdvice,为所有 Controller 添加通用模型属性。

示例

java 复制代码
@ControllerAdvice(basePackages = "com.example.controller")
public class GlobalModelAttribute {
   // 为所有请求添加当前登录用户信息
   @ModelAttribute("currentUser")
   public User getCurrentUser(HttpServletRequest request) {
       String token = request.getHeader("token");
       return UserContext.getCurrentUser(token); // 从上下文获取登录用户
   }
}
// 页面中可直接使用${currentUser.name}
@Controller
@RequestMapping("/user")
public class UserController {
   @GetMapping("/info")
   public String userInfo() {
       return "user/info"; // 页面渲染时可获取currentUser
   }
}

5. @CookieValue

@CookieValue 用于从 HTTP Cookie 中获取指定值,绑定到 Controller 方法参数。

  • 核心特性:支持默认值,避免 Cookie 不存在时抛异常。

属性说明:

属性名 说明
required 是否必须存在
defaultValue 默认值

示例

java 复制代码
@RestController
@RequestMapping("/cookie")
public class CookieController {
   @GetMapping("/get")
   public Result<String> getCookie(
       @CookieValue(value = "userId", required = false, defaultValue = "0") String userId
   ) {
       return Result.success("用户ID:" + userId);
   }
}

6. @MatrixVariable

@MatrixVariable 用于获取URL 中的矩阵变量(以;分隔的键值对),如/user/info;id=1;name=test

  • 注意:Spring MVC 默认禁用矩阵变量,需手动开启:
java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {
   @Override
   public void configurePathMatch(PathMatchConfigurer configurer) {
       UrlPathHelper urlPathHelper = new UrlPathHelper();
       urlPathHelper.setRemoveSemicolonContent(false); // 开启矩阵变量
       configurer.setUrlPathHelper(urlPathHelper);
   }
}

属性说明:

属性名 说明 补充说明
value 矩阵变量名 name等价
name 矩阵变量名 name = "id"
pathVar 路径变量名 匹配指定路径变量中的矩阵变量,如pathVar = "userPath"
required 是否必须存在 true(默认):不存在抛异常;② false:不存在则为 null
defaultValue 默认值 变量不存在时使用

示例

java 复制代码
@RestController
@RequestMapping("/matrix")
public class MatrixVariableController {
   // 匹配URL:/matrix/user/info;id=1;name=test
   @GetMapping("/user/{userPath}")
   public Result<Map<String, String>> getMatrixVariable(
       @MatrixVariable(name = "id", pathVar = "userPath") String id,
       @MatrixVariable(name = "name", pathVar = "userPath", defaultValue = "guest") String name
   ) {
       Map<String, String> data = new HashMap<>();
       data.put("id", id);
       data.put("name", name);
       return Result.success(data);
   }
}

7. @PathVariable

@PathVariable 用于获取 URL 路径中的变量(以{}声明),是 RESTful API 的核心注解。

属性说明:

属性名 说明
required 是否必须存在
defaultValue 默认值

示例

java 复制代码
@RestController
@RequestMapping("/path")
public class PathVariableController {
   // 匹配URL:/path/user/123/detail
   @GetMapping("/user/{userId}/detail")
   public Result<User> getUser(
       @PathVariable(value = "userId", required = true) Long userId
   ) {
       User user = new User(userId, "测试用户");
       return Result.success(user);
   }
}

8. @RequestAttribute

@RequestAttribute 用于获取 HTTP Request 中的属性值,适用于请求转发 / 包含场景(如过滤器中设置的属性)。

属性说明:

属性名 说明
required 是否必须存在

示例

java 复制代码
@RestController
@RequestMapping("/request")
public class RequestAttributeController {
   // 设置请求属性
   @GetMapping("/setAttr")
   public String setRequestAttribute(HttpServletRequest request) {
       request.setAttribute("traceId", UUID.randomUUID().toString());
       return "forward:/request/getAttr"; // 请求转发
   }
   // 获取请求属性
   @GetMapping("/getAttr")
   public Result<String> getRequestAttribute(
       @RequestAttribute(value = "traceId", required = false) String traceId
   ) {
       return Result.success("追踪ID:" + traceId);
   }
}

9. @RequestPart

@RequestPart 用于处理multipart/form-data类型的请求,适用于文件上传、复杂参数提交(如 JSON、XML)。

  • 核心区别:@RequestParam仅处理简单表单字段,@RequestPart支持复杂类型和文件。

示例(文件上传 + JSON 参数)

java 复制代码
@RestController
@RequestMapping("/upload")
public class RequestPartController {
   // 接收文件+JSON参数
   @PostMapping("/file")
   public Result<String> uploadFile(
       @RequestPart("file") MultipartFile file, // 上传的文件
       @RequestPart("user") @Valid User user // JSON格式的用户信息
   ) {
       String fileName = file.getOriginalFilename();
       // 处理文件上传和用户信息
       return Result.success("文件:" + fileName + " 上传成功,用户:" + user.getName());
   }
}
// 请求示例(Postman):
// Content-Type: multipart/form-data
// 表单字段:
// - file:选择文件
// - user:{"name":"test","age":20}(JSON格式)

10. @ResponseStatus

@ResponseStatus 用于设置 HTTP 响应状态码,可标注在 Controller 方法或异常类上。

  • 核心用途:自定义异常的响应状态码,或修改正常请求的状态码。

属性说明:

属性名 说明 补充说明
value 响应状态码 HttpStatus.CREATED(201)、HttpStatus.BAD_REQUEST(400)
code 同 value 语义等价,推荐使用 value
reason 响应描述 状态码对应的描述信息,如reason = "参数错误"

示例 1:标注在方法上

java 复制代码
@RestController
@RequestMapping("/status")
public class ResponseStatusController {
   // 响应状态码:201 Created
   @PostMapping("/create")
   @ResponseStatus(value = HttpStatus.CREATED, reason = "资源创建成功")
   public Result<Void> createResource() {
       // 处理资源创建逻辑
       return Result.success();
   }
}

示例 2:标注在异常类上

java 复制代码
// 自定义异常,指定响应状态码
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "资源不存在")
public class ResourceNotFoundException extends RuntimeException {
   public ResourceNotFoundException(String message) {
       super(message);
   }
}
// Controller中抛出异常,自动返回404
@GetMapping("/resource/{id}")
public Result<Resource> getResource(@PathVariable Long id) {
   Resource resource = resourceService.getById(id);
   if (resource == null) {
       throw new ResourceNotFoundException("资源ID:" + id + " 不存在");
   }
   return Result.success(resource);
}

11. @SessionAttribute

@SessionAttribute 用于从 HTTP Session 中获取指定属性值,适用于会话级数据(如登录状态、用户信息)。

属性说明:

属性名 说明
required 是否必须存在
defaultValue 默认值

示例

java 复制代码
@RestController
@RequestMapping("/session")
public class SessionAttributeController {
   // 设置Session属性
   @GetMapping("/login")
   public Result<Void> login(HttpSession session) {
       User user = new User(1L, "admin");
       session.setAttribute("loginUser", user); // 存储登录用户
       return Result.success("登录成功");
   }
   // 获取Session属性
   @GetMapping("/user")
   public Result<User> getLoginUser(
       @SessionAttribute(value = "loginUser", required = false) User loginUser
   ) {
       if (loginUser == null) {
           return Result.fail(401, "未登录");
       }
       return Result.success(loginUser);
   }
}

三、事务管理相关注解

事务管理注解是 Spring 实现声明式事务的核心,通过注解快速配置事务属性,替代传统 XML 事务配置。

1. @Transactional

@Transactional 是声明式事务的核心注解,标注在类或方法上,指定该类 / 方法的事务属性。

  • 类级注解:所有 public 方法继承事务属性;
  • 方法级注解:优先级高于类级,可单独配置;
  • 底层依赖:AOP 动态代理实现事务增强,默认仅捕获运行时异常(RuntimeException)。

属性说明:

属性名 说明 补充说明
value 事务管理器名称 value = "transactionManager",多数据源时指定
transactionManager 同 value 语义更清晰,推荐使用
propagation 事务传播行为 枚举值,如REQUIRED(默认)、REQUIRES_NEWSUPPORTS
isolation 事务隔离级别 枚举值,如DEFAULT(默认,跟随数据库)、READ_COMMITTEDSERIALIZABLE
timeout 事务超时时间(秒) 默认为 - 1(无超时),超时抛出TransactionTimedOutException
readOnly 是否只读事务 true:只读(查询操作,优化性能);② false(默认):读写事务
rollbackFor 触发回滚的异常类型 数组形式,如rollbackFor = {SQLException.class, BusinessException.class}
rollbackForClassName 触发回滚的异常类名 字符串数组,如rollbackForClassName = "java.sql.SQLException"
noRollbackFor 不触发回滚的异常类型 数组形式,如noRollbackFor = IllegalArgumentException.class
noRollbackForClassName 不触发回滚的异常类名 字符串数组,如noRollbackForClassName = "java.lang.IllegalArgumentException"

示例

java 复制代码
@Service
@Transactional(readOnly = true) // 类级:所有public方法默认只读事务
public class OrderService {
   // 方法级:覆盖类级配置,读写事务,超时30秒,指定异常回滚
   @Transactional(
       propagation = Propagation.REQUIRED,
       isolation = Isolation.READ_COMMITTED,
       timeout = 30,
       readOnly = false,
       rollbackFor = {OrderException.class, SQLException.class}
   )
   public void createOrder(OrderDTO orderDTO) {
       // 订单创建逻辑(增删改操作)
       orderMapper.insert(orderDTO);
       inventoryMapper.deduct(orderDTO.getProductId(), orderDTO.getQuantity());
   }
   // 继承类级只读事务
   public OrderDTO getOrderById(Long orderId) {
       return orderMapper.selectById(orderId);
   }
}

2. @EnableTransactionManagement

@EnableTransactionManagement 用于启用 Spring 声明式事务管理,标注在配置类上。

  • 核心作用:激活 Spring 的事务注解驱动,自动扫描@Transactional标注的 Bean 并生成代理;
  • 兼容模式:支持 Spring AOP 和 AspectJ 两种代理方式。

属性说明:

属性名 说明 补充说明
proxyTargetClass 是否使用 CGLIB 代理 true:强制 CGLIB 代理(类代理);② false(默认):优先 JDK 动态代理(接口代理)
mode 事务代理模式 枚举值:PROXY(默认,Spring AOP 代理)、ASPECTJ(AspectJ 代理,需额外依赖)
order 事务切面优先级 数值越小优先级越高,默认Ordered.LOWEST_PRECEDENCE(最低)

示例

java 复制代码
@Configuration
@EnableTransactionManagement(proxyTargetClass = true) // 启用事务管理,使用CGLIB代理
@MapperScan("com.example.mapper")
public class TransactionConfig {
   // 配置事务管理器(基于数据源)
   @Bean
   public PlatformTransactionManager transactionManager(DataSource dataSource) {
       return new DataSourceTransactionManager(dataSource);
   }
}

四、数据访问相关注解

数据访问注解涵盖 Spring Data JPA、MyBatis 等持久层框架的核心注解,简化数据操作逻辑。

1. Spring Data JPA 核心注解

(1)@RepositoryRestResource

@RepositoryRestResource 用于 Spring Data REST,将 Repository 自动暴露为 RESTful API,无需手动编写 Controller。

属性说明:

属性名 说明 补充说明
path API 路径 path = "users",访问路径/users
collectionResourceRel 集合资源关系名 用于 HATEOAS 链接,如collectionResourceRel = "userList"
itemResourceRel 单个资源关系名 itemResourceRel = "user"
exported 是否暴露 API true(默认):暴露;② false:不暴露
excerptProjection 默认投影 指定默认返回的字段投影类

示例

java 复制代码
// 自动暴露REST API:/users(GET/POST/PUT/DELETE)
@RepositoryRestResource(path = "users", collectionResourceRel = "userList")
public interface UserRepository extends JpaRepository<User, Long> {
   // 自动生成API:/users/search/byName?name=xxx
   @RestResource(path = "byName", rel = "findByName")
   List<User> findByNameContaining(@Param("name") String name);
}
(2)@Query

@Query 用于自定义 JPQL/SQL 查询,标注在 Repository 方法上。

属性说明:

属性名 说明 补充说明
value 查询语句 JPQL(默认)或 SQL(需配合nativeQuery = true
nativeQuery 是否原生 SQL true:原生 SQL;② false(默认):JPQL
countQuery 计数查询语句 配合分页查询,返回总条数
countProjection 计数投影 简化计数查询,如countProjection = "id"
namedParameters 是否支持命名参数 true(默认):支持@Param命名参数;② false:仅支持位置参数

示例

java 复制代码
public interface ProductRepository extends JpaRepository<Product, Long> {
   // JPQL查询(参数使用:name)
   @Query("SELECT p FROM Product p WHERE p.name LIKE %:name% AND p.price <= :maxPrice")
   List<Product> findByCondition(@Param("name") String name, @Param("maxPrice") BigDecimal maxPrice);
   // 原生SQL查询
   @Query(
       value = "SELECT * FROM product WHERE category_id = ?1 AND stock > 0",
       nativeQuery = true
   )
   List<Product> findAvailableByCategoryId(Long categoryId);
   // 分页+计数查询
   @Query(value = "SELECT p FROM Product p WHERE p.createTime >= :startTime",
          countQuery = "SELECT COUNT(p.id) FROM Product p WHERE p.createTime >= :startTime")
   Page<Product> findByCreateTimeAfter(@Param("startTime") LocalDateTime startTime, Pageable pageable);
}
(3)@Modifying

@Modifying 配合@Query使用,标识该查询为修改操作(INSERT/UPDATE/DELETE),需在事务中执行。

示例

java 复制代码
public interface UserRepository extends JpaRepository<User, Long> {
   @Modifying
   @Query("UPDATE User u SET u.status = :status WHERE u.id IN :ids")
   @Transactional // 修改操作需事务支持
   int batchUpdateStatus(@Param("status") Integer status, @Param("ids") List<Long> ids);
}

2. MyBatis 核心注解

(1)@Mapper

@Mapper 标识接口为 MyBatis 映射器接口,MyBatis 会自动扫描并生成代理实现类。

  • 替代方案:可通过@MapperScan(配置类注解)批量扫描包下的 Mapper 接口。

示例

java 复制代码
// 单个Mapper接口标注
@Mapper
public interface UserMapper {
   @Select("SELECT * FROM user WHERE id = #{id}")
   User selectById(Long id);
   @Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
   @Options(useGeneratedKeys = true, keyProperty = "id") // 自动生成主键并回写
   int insert(User user);
}
// 配置类批量扫描(推荐)
@Configuration
@MapperScan("com.example.mapper") // 扫描该包下所有Mapper接口
public class MyBatisConfig {
}
(2)MyBatis 查询 / 操作注解

MyBatis 提供一系列注解替代 XML 映射文件,核心包括:

  • @Select:查询操作
  • @Insert:插入操作
  • @Update:更新操作
  • @Delete:删除操作
  • @ResultMap:引用 XML 中的结果映射
  • @Param:指定方法参数名(用于 SQL 中 #{name} 引用)

示例

java 复制代码
@Mapper
public interface OrderMapper {
   // 查询(关联查询,使用@Results映射)
   @Select("SELECT o.id, o.order_no, o.user_id, u.name user_name " +
           "FROM order o LEFT JOIN user u ON o.user_id = u.id " +
           "WHERE o.id = #{id}")
   @Results({
       @Result(column = "id", property = "id", id = true),
       @Result(column = "order_no", property = "orderNo"),
       @Result(column = "user_id", property = "userId"),
       @Result(column = "user_name", property = "userName")
   })
   OrderVO selectOrderVOById(Long id);
   // 批量插入
   @Insert("<script>" +
           "INSERT INTO order(user_id, order_no, amount) " +
           "VALUES" +
           "<foreach collection='list' item='item' separator=','>" +
           "(#{item.userId}, #{item.orderNo}, #{item.amount})" +
           "</foreach>" +
           "</script>")
   int batchInsert(@Param("list") List<Order> orderList);
   // 更新
   @Update("UPDATE order SET status = #{status} WHERE id = #{id}")
   int updateStatus(@Param("id") Long id, @Param("status") Integer status);
}

五、Spring Security 安全相关注解

Spring Security 注解用于实现权限控制、身份认证相关功能,简化安全配置。

1. @EnableWebSecurity

@EnableWebSecurity 用于启用 Spring Security 的 Web 安全支持,标注在安全配置类上。

  • 核心作用:激活 Spring Security 的自动配置,加载默认安全规则(如登录页面、CSRF 防护等)。

示例

java 复制代码
@Configuration
@EnableWebSecurity // 启用Web安全
@EnableMethodSecurity // 启用方法级权限控制(Spring Security 6+)
public class SecurityConfig {
   // 配置用户认证(内存用户示例)
   @Bean
   public UserDetailsService userDetailsService() {
       UserDetails admin = User.withUsername("admin")
               .password(passwordEncoder().encode("123456"))
               .roles("ADMIN")
               .build();
       UserDetails user = User.withUsername("user")
               .password(passwordEncoder().encode("123456"))
               .roles("USER")
               .build();
       return new InMemoryUserDetailsManager(admin, user);
   }
   // 密码加密器
   @Bean
   public PasswordEncoder passwordEncoder() {
       return new BCryptPasswordEncoder();
   }
   // 配置安全规则
   @Bean
   public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
       http
           .authorizeHttpRequests(auth -> auth
               .requestMatchers("/public/**").permitAll() // 公开路径
               .requestMatchers("/admin/**").hasRole("ADMIN") // 仅ADMIN角色可访问
               .anyRequest().authenticated() // 其他路径需认证
           )
           .formLogin(form -> form.permitAll()) // 启用默认登录页面
           .logout(logout -> logout.permitAll()); // 启用注销功能
       return http.build();
   }
}

2. @EnableMethodSecurity

@EnableMethodSecurity(Spring Security 6+,替代旧版@EnableGlobalMethodSecurity)用于启用方法级权限控制,支持@PreAuthorize@PostAuthorize等注解。

属性说明:

属性名 说明 补充说明
prePostEnabled 是否启用 @PreAuthorize/@PostAuthorize true(默认):启用;② false:禁用
securedEnabled 是否启用 @Secured true:启用;② false(默认):禁用
jsr250Enabled 是否启用 JSR-250 注解(如 @RolesAllowed) true:启用;② false(默认):禁用

3. 方法级权限注解

(1)@PreAuthorize

@PreAuthorize 方法执行前进行权限校验,支持 SpEL 表达式,灵活控制访问权限。

示例

java 复制代码
@Service
public class ResourceService {
   // 仅ADMIN角色可访问
   @PreAuthorize("hasRole('ADMIN')")
   public void deleteResource(Long id) {
       // 删除资源逻辑
   }
   // 仅本人或ADMIN可访问(SpEL表达式,#userId为方法参数)
   @PreAuthorize("authentication.principal.username == #username or hasRole('ADMIN')")
   public UserDTO getUserInfo(String username) {
       // 查询用户信息
   }
   // 权限表达式结合自定义方法(需注册Bean:customPermissionEvaluator)
   @PreAuthorize("@customPermissionEvaluator.hasPermission(#orderId, authentication)")
   public OrderDTO getOrderById(Long orderId) {
       // 查询订单
   }
}
(2)@PostAuthorize

@PostAuthorize 方法执行后进行权限校验,适用于需要根据返回结果判断权限的场景(如数据权限)。

示例

java 复制代码
@Service
public class OrderService {
   // 方法执行后校验:返回的订单所属用户与当前登录用户一致
   @PostAuthorize("returnObject.userId == authentication.principal.id")
   public OrderDTO getOrderById(Long orderId) {
       return orderMapper.selectById(orderId);
   }
}
(3)@Secured

@Secured 用于基于角色的权限控制,仅支持角色名称(需以ROLE_前缀开头,或配置rolePrefix)。

示例

java 复制代码
@Service
public class UserService {
   // 仅ROLE_ADMIN角色可访问(注意前缀ROLE_)
   @Secured("ROLE_ADMIN")
   public void batchDelete(List<Long> ids) {
       userMapper.batchDelete(ids);
   }
   // 多角色支持(OR关系)
   @Secured({"ROLE_ADMIN", "ROLE_OPERATOR"})
   public void updateUserStatus(Long id, Integer status) {
       userMapper.updateStatus(id, status);
   }
}
(4)@RolesAllowed(JSR-250)

@RolesAllowed 是 JSR-250 标准注解,功能与@Secured类似,支持角色权限控制。

示例

java 复制代码
@Service
public class ProductService {
   // 支持ROLE_USER或ROLE_ADMIN角色
   @RolesAllowed({"USER", "ADMIN"})
   public List<ProductDTO> getProductList() {
       return productMapper.selectAll();
   }
}

4. @AuthenticationPrincipal

@AuthenticationPrincipal 用于获取当前登录用户的认证信息(Authentication中的Principal),简化用户信息获取。

示例

java 复制代码
@RestController
@RequestMapping("/user")
public class UserController {
   // 获取当前登录用户的用户名(Principal为String类型)
   @GetMapping("/info")
   public Result<UserInfo> getUserInfo(@AuthenticationPrincipal String username) {
       UserInfo userInfo = userService.getUserByUsername(username);
       return Result.success(userInfo);
   }
   // 获取自定义UserDetails对象(需实现UserDetails接口)
   @GetMapping("/profile")
   public Result<CustomUserDetails> getProfile(@AuthenticationPrincipal CustomUserDetails userDetails) {
       return Result.success(userDetails);
   }
}

5. @CrossOrigin

@CrossOrigin 用于解决跨域资源共享(CORS)问题,标注在 Controller 或方法上,允许跨域请求访问。

  • 核心场景:前后端分离架构中,前端域名与后端 API 域名不一致时配置;
  • 底层原理:自动添加Access-Control-*响应头,支持预检请求(OPTIONS)。

属性说明:

属性名 说明 补充说明
origins 允许的跨域源 数组形式,如origins = {"``https://example.com``", "``http://localhost:8080``"}*表示允许所有(不推荐生产环境)
allowedHeaders 允许的请求头 数组形式,如allowedHeaders = {"Content-Type", "Authorization"}*表示允许所有
methods 允许的请求方法 数组形式,如methods = {RequestMethod.GET, RequestMethod.POST},默认允许所有请求方法
exposedHeaders 允许前端访问的响应头 数组形式,如exposedHeaders = "X-Total-Count",默认仅暴露基本响应头
allowCredentials 是否允许携带 Cookie true:允许(需前端配合设置withCredentials: true);② false(默认):不允许
maxAge 预检请求缓存时间(秒) 默认为 1800 秒(30 分钟),减少预检请求次数

示例

java 复制代码
// 类级配置:所有方法允许跨域
@RestController
@RequestMapping("/api")
@CrossOrigin(
   origins = {"https://example.com", "http://localhost:8080"},
   allowedHeaders = "*",
   allowCredentials = true,
   maxAge = 3600
)
public class ApiController {
   // 方法级配置:覆盖类级,仅允许GET/POST方法
   @CrossOrigin(methods = {RequestMethod.GET, RequestMethod.POST})
   @GetMapping("/data")
   public Result<List<DataDTO>> getData() {
       return Result.success(dataService.list());
   }
}

六、其他常用核心注解

1. 异步相关注解

(1)@EnableAsync

@EnableAsync 用于启用 Spring 异步方法支持,标注在配置类上。

  • 核心作用:激活 Spring 对@Async注解的识别,通过线程池执行异步方法。

属性说明:

属性名 说明 补充说明
proxyTargetClass 是否使用 CGLIB 代理 true:类代理;② false(默认):接口代理
mode 代理模式 PROXY(默认)或ASPECTJ(需额外依赖)
order 异步切面优先级 数值越小优先级越高,默认最低

示例

java 复制代码
@Configuration
@EnableAsync(proxyTargetClass = true) // 启用异步支持
public class AsyncConfig {
   // 配置自定义线程池(推荐)
   @Bean
   public Executor taskExecutor() {
       ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
       executor.setCorePoolSize(5); // 核心线程数
       executor.setMaxPoolSize(10); // 最大线程数
       executor.setQueueCapacity(20); // 队列容量
       executor.setKeepAliveSeconds(60); // 空闲线程存活时间
       executor.setThreadNamePrefix("Async-"); // 线程名前缀
       executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
       executor.initialize();
       return executor;
   }
}
(2)@Async

@Async 标注方法为异步方法,Spring 会通过线程池异步执行(非当前线程阻塞)。

  • 异步方法不能在同一个类中调用(代理失效,如事务失效);
  • 无返回值用void,有返回值用Future<T>CompletableFuture<T>

示例

java 复制代码
@Service
public class AsyncService {
   // 无返回值异步方法
   @Async("taskExecutor") // 指定线程池(对应AsyncConfig中的Bean名称)
   public void sendNotice(Long userId, String content) {
       // 异步执行:发送短信/邮件通知(无返回值)
       noticeClient.send(userId, content);
   }
   // 有返回值异步方法(CompletableFuture支持链式调用)
   @Async
   public CompletableFuture<Boolean> exportData(String condition) {
       // 异步执行:数据导出逻辑
       boolean success = exportService.doExport(condition);
       return CompletableFuture.completedFuture(success);
   }
}
// 调用示例
@Controller
public class ExportController {
   @Autowired
   private AsyncService asyncService;
   @GetMapping("/export")
   public Result<String> export(String condition) {
       CompletableFuture<Boolean> future = asyncService.exportData(condition);
       future.whenComplete((success, ex) -> {
           if (success) {
               // 导出成功回调
           } else {
               // 导出失败处理
           }
       });
       return Result.success("导出任务已启动,请稍后查看结果");
   }
}

2. 缓存相关注解

(1)@EnableCaching

@EnableCaching 用于启用 Spring 缓存支持,标注在配置类上。

  • 核心作用:激活 Spring 对缓存注解(@Cacheable@CachePut等)的识别,整合第三方缓存(如 Redis、Caffeine)。

示例

java 复制代码
@Configuration
@EnableCaching // 启用缓存支持
public class CacheConfig {
   // 配置Redis缓存管理器(需引入spring-boot-starter-data-redis依赖)
   @Bean
   public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
       RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
               .entryTtl(Duration.ofMinutes(30)) // 默认缓存过期时间30分钟
               .serializeKeysWith(RedisSerializationContext.SerializationPair
                       .fromSerializer(new StringRedisSerializer()))
               .serializeValuesWith(RedisSerializationContext.SerializationPair
                       .fromSerializer(new GenericJackson2JsonRedisSerializer()));
       // 自定义不同缓存的过期时间
       Map<String, RedisCacheConfiguration> cacheConfigs = new HashMap<>();
       cacheConfigs.put("userCache", config.entryTtl(Duration.ofHours(1)));
       cacheConfigs.put("productCache", config.entryTtl(Duration.ofMinutes(10)));
       return RedisCacheManager.builder(connectionFactory)
               .cacheDefaults(config)
               .withInitialCacheConfigurations(cacheConfigs)
               .build();
   }
}
(2)核心缓存注解
注解 作用 核心属性
@Cacheable 查询缓存:存在则返回缓存,不存在则执行方法并缓存结果 value(缓存名称)、key(缓存键,SpEL 表达式)、condition(缓存条件)
@CachePut 更新缓存:执行方法后更新缓存(不查询缓存) @Cacheable,用于新增 / 修改操作
@CacheEvict 删除缓存:执行方法后删除指定缓存 @CacheableallEntries(是否删除所有缓存)、beforeInvocation(是否执行前删除)
@Caching 组合缓存:一个方法配置多个缓存注解 cacheableputevict(数组形式)
@CacheConfig 类级缓存配置:统一指定value(缓存名称),方法级可覆盖 value(默认缓存名称)

示例

java 复制代码
@Service
@CacheConfig(value = "productCache") // 类级:默认缓存名称
public class ProductService {
   // 查询缓存:key为产品ID,条件为ID>0
   @Cacheable(key = "#id", condition = "#id > 0")
   public ProductDTO getProductById(Long id) {
       // 缓存不存在时执行:查询数据库
       return productMapper.selectById(id);
   }
   // 更新缓存:新增产品后缓存结果(key为返回的ID)
   @CachePut(key = "#result.id")
   public ProductDTO addProduct(ProductForm form) {
       Product product = new Product();
       BeanUtils.copyProperties(form, product);
       productMapper.insert(product);
       ProductDTO dto = new ProductDTO();
       BeanUtils.copyProperties(product, dto);
       return dto;
   }
   // 删除缓存:删除产品后删除对应缓存,同时清空所有产品列表缓存
   @Caching(evict = {
       @CacheEvict(key = "#id"), // 删除单个产品缓存
       @CacheEvict(value = "productListCache", allEntries = true) // 清空列表缓存
   })
   public void deleteProduct(Long id) {
       productMapper.deleteById(id);
   }
   // 条件缓存:查询列表时缓存,条件为分类ID不为空
   @Cacheable(value = "productListCache", key = "#categoryId", condition = "#categoryId != null")
   public List<ProductDTO> getProductByCategoryId(Long categoryId) {
       return productMapper.selectByCategoryId(categoryId);
   }
}

3. 事件相关注解

(1)@EventListener

@EventListener 标注方法为 Spring 事件监听器,监听指定类型的事件。

  • 核心场景:解耦业务逻辑(如订单创建后触发库存扣减、日志记录等);
  • 支持事件:Spring 内置事件(如ContextRefreshedEvent)或自定义事件。

示例

java 复制代码
// 1. 定义自定义事件(继承ApplicationEvent)
public class OrderCreatedEvent extends ApplicationEvent {
   private OrderDTO orderDTO;
   public OrderCreatedEvent(Object source, OrderDTO orderDTO) {
       super(source);
       this.orderDTO = orderDTO;
   }
   // getter/setter
}
// 2. 发布事件(在业务方法中)
@Service
public class OrderService {
   @Autowired
   private ApplicationEventPublisher eventPublisher;
   @Transactional
   public void createOrder(OrderDTO orderDTO) {
       // 订单创建逻辑
       orderMapper.insert(orderDTO);
       // 发布事件(异步发布需配合@Async)
       eventPublisher.publishEvent(new OrderCreatedEvent(this, orderDTO));
   }
}
// 3. 监听事件(多个监听器可同时监听)
@Service
public class OrderEventListener {
   // 同步监听:与发布事件的事务同线程
   @EventListener(OrderCreatedEvent.class)
   public void handleOrderCreated(OrderCreatedEvent event) {
       OrderDTO orderDTO = event.getOrderDTO();
       // 执行后续逻辑:如日志记录
       logService.recordOrderLog(orderDTO.getId(), "订单创建成功");
   }
   // 异步监听:通过@Async指定线程池,不阻塞主线程
   @Async("taskExecutor")
   @EventListener(OrderCreatedEvent.class)
   public void handleInventoryDeduct(OrderCreatedEvent event) {
       OrderDTO orderDTO = event.getOrderDTO();
       // 异步执行:库存扣减
       inventoryService.deduct(orderDTO.getProductId(), orderDTO.getQuantity());
   }
}
(2)@TransactionalEventListener

@TransactionalEventListener@EventListener的事务增强版,支持事务生命周期绑定。

  • 核心特性:事件触发时机与事务状态关联(如事务提交后、回滚后),避免事务未提交时触发后续逻辑。

属性说明:

属性名 说明 补充说明
phase 事务阶段 枚举值:BEFORE_COMMIT(提交前)、AFTER_COMMIT(提交后,默认)、AFTER_ROLLBACK(回滚后)、AFTER_COMPLETION(完成后,无论提交 / 回滚)
fallbackExecution 无事务时是否执行 true:无事务时也执行;② false(默认):仅事务中执行

示例

java 复制代码
@Service
public class OrderEventListener {
   // 事务提交后执行:确保订单创建成功后再发送通知
   @TransactionalEventListener(
       value = OrderCreatedEvent.class,
       phase = TransactionPhase.AFTER_COMMIT,
       fallbackExecution = false
   )
   public void sendOrderNotice(OrderCreatedEvent event) {
       OrderDTO orderDTO = event.getOrderDTO();
       // 事务提交后执行:发送短信/邮件通知
       noticeService.send(orderDTO.getUserId(), "您的订单已创建成功,订单号:" + orderDTO.getOrderNo());
   }
}

4. 依赖注入相关补充注解

(1)@Resource(JSR-250)

@Resource 是 JSR-250 标准注解,用于依赖注入,与@Autowired功能类似,区别如下:

  • @Autowired:Spring 提供,按类型注入,需配合@Qualifier指定名称;
  • @Resource:JDK 标准,默认按名称注入,名称匹配失败则按类型注入。

属性说明:

属性名 说明 补充说明
name 注入 Bean 的名称 name = "userService",优先按名称匹配
type 注入 Bean 的类型 type = UserService.class,按类型匹配
lookup 查找方式 仅用于 EJB,Spring 中很少使用

示例

java 复制代码
@Service
public class OrderService {
   // 按名称注入(Bean名称为userService)
   @Resource(name = "userService")
   private UserService userService;
   // 按类型注入(仅当存在唯一UserMapper类型Bean时生效)
   @Resource(type = UserMapper.class)
   private UserMapper userMapper;
   // 无属性:默认按字段名(orderMapper)匹配Bean名称
   @Resource
   private OrderMapper orderMapper;
}
(2)@Inject(JSR-330)

@Inject 是 JSR-330 标准注解,用于依赖注入,功能与@Autowired类似,需引入javax.inject依赖。

  • 特点:无属性,仅按类型注入,需配合@Named指定 Bean 名称。

示例

xml 复制代码
<!-- 引入依赖(Maven) -->
<dependency>
   <groupId>javax.inject</groupId>
   <artifactId>javax.inject</artifactId>
   <version>1</version>
</dependency>
java 复制代码
@Service
public class ProductService {
   // 按类型注入
   @Inject
   private ProductMapper productMapper;
   // 按名称注入(配合@Named)
   @Inject
   @Named("userService")
   private UserService userService;
}

七、注解使用注意事项总结

  1. 代理失效问题
  • @Transactional@Async@Cacheable等注解依赖 Spring AOP 代理,同一类中方法调用会导致代理失效;
  • 解决方案:通过ApplicationContext获取 Bean 调用,或拆分业务逻辑到不同类。
  1. 事务相关注意
  • @Transactional默认仅回滚RuntimeException,检查型异常(如SQLException)需通过rollbackFor指定;
  • 多数据源场景需通过transactionManager属性指定对应的事务管理器。
  1. 缓存相关注意
  • @Cacheablekey需使用 SpEL 表达式(如#id),避免硬编码;
  • 缓存对象需实现序列化(如 Redis 缓存时),否则会抛出序列化异常。
  1. 权限注解注意
  • Spring Security 6 + 推荐使用@EnableMethodSecurity替代旧版@EnableGlobalMethodSecurity
  • @Secured注解的角色名称默认需带ROLE_前缀,可通过配置rolePrefix = ""取消前缀。
  1. 依赖注入选择
  • 优先使用@Autowired(Spring 原生,支持更多特性);
  • 跨框架兼容场景可使用@Resource(JSR-250)或@Inject(JSR-330)。

通过本文整理的 Spring 核心注解,可覆盖大多数开发场景,合理使用注解能大幅简化配置、解耦业务逻辑,提升开发效率。实际开发中需结合具体场景选择合适的注解,并注意避免常见陷阱(如代理失效、事务回滚异常等)。

相关推荐
长沙古天乐1 小时前
Spring Boot应用中配置消费端随服务启动循环消费消息
spring boot·后端·linq
葡萄城技术团队1 小时前
Excel 文件到底是怎么坏掉的?深入 OOXML 底层原理讲解修复策略
android·java·excel
照物华1 小时前
MySQL 软删除 (Soft Delete) 与唯一索引 (Unique Constraint) 的冲突与解决
java·mysql
mjhcsp1 小时前
C++ 后缀自动机(SAM):原理、实现与应用全解析
java·c++·算法
wadesir1 小时前
掌握 Rust 中的浮点数处理(Rust f64 浮点数与标准库详解)
开发语言·后端·rust
IT_陈寒1 小时前
React 18新特性实战:这5个Hook组合让我少写50%状态管理代码
前端·人工智能·后端
HashTang1 小时前
【AI 编程实战】第 1 篇:TRAE SOLO 模式 10 倍速开发商业级全栈小程序
前端·后端·ai编程
张np1 小时前
java基础-Vector(向量)
java
光头程序员1 小时前
学习笔记——常识解答之垃圾回收机制
java·笔记·学习