开发中反复查的 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 核心注解,可覆盖大多数开发场景,合理使用注解能大幅简化配置、解耦业务逻辑,提升开发效率。实际开发中需结合具体场景选择合适的注解,并注意避免常见陷阱(如代理失效、事务回滚异常等)。

相关推荐
Rust研习社24 分钟前
组合真的优于继承吗?为什么 Rust 和 Go 都拥抱组合舍弃继承?
后端·rust·编程语言
IT_陈寒1 小时前
JavaScript的闭包把我坑惨了,说好的内存会自动回收呢?
前端·人工智能·后端
CaffeinePro2 小时前
Pydantic深度使用:数据校验、枚举、ORM映射
后端·fastapi
Chenyiax2 小时前
从 Chat 到 Responses:OpenAI API 抽象为什么变了?
后端
MariaH2 小时前
Koa和Express的区别
后端
MariaH2 小时前
Koa框架的使用
后端
luckdewei3 小时前
那个用 passlib 做认证的新同事,上线第一天就把用户密码写进了日志
后端
ping某5 小时前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
JustHappy5 小时前
我汇总了身边朋友的经历才发现,其实第一份实习是最难找的......
前端·后端·面试
uhakadotcom5 小时前
在python 的 工程化架构中 ,什么是 薄包装器层?
后端·面试·github