🎉🎉《Spring Boot实战案例合集》目前已更新176个案例,我们将持续不断的更新。文末有电子书目录。
💪💪永久更新承诺
我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务。
💌💌如何获取
订阅我们的合集《点我订阅》,并通过私信联系我们,我们将第一时间将电子书发送给您。
环境:SpringBoot3.4.2
1. 简介
在日常开发中,我们常常只熟悉 Spring Boot 的基础注解,却忽略了那些能大幅提升代码质量与可维护性的“宝藏”功能。这些注解不仅简化了配置、增强了类型安全,还让应用更具弹性与可读性。掌握这些隐藏却强大的注解,是进阶 Spring Boot 高手的必经之路。本篇文章精选 9 个实用又易被忽视的注解,涵盖条件化配置、事件驱动、不可变配置等核心场景,助你写出更优雅、更健壮的代码。
2.1 强大的SpEL条件注解@ConditionalOnExpression
相比@ConditionalOnProperty 条件判断相对简单直接;@ConditionalOnExpression 则不同,它凭借 SpEL 可综合多因素,如属性、方法结果等,构建复杂逻辑,比前者具备更强大的配置能力。
public class CacheConfiguration {CacheManager cacheManager() {return new ConcurrentMapCacheManager() ;}}
在这个示例中,我们创建了一个条件化的缓存配置,该配置仅在特定情况下才会生效。SpEL 表达式检查两个条件:
${app.cache.enabled:false}:验证 application.properties 中是否启用了缓存功能(如果未指定,则默认为 false)'${spring.profiles.active}' != 'test':确保当前所处的环境不是测试(test)环境
你还可以调用其它的Bean方法
public class AdvancedFeatureConfig {}
只有featureChecker bean的isAdvancedFeatureAvailable方法返回true才会生效。
2.2 @ConstructorBinding 实现不可变配置
告别可变的配置属性!在 Spring Boot 中,将 @ConfigurationProperties 与 @ConstructorBinding 结合使用,可以创建不可变(immutable)的配置类,从而提升应用的安全性、线程安全性和代码的可维护性。
public class AppProperties {private final Boolean enabled;private final String apiKey;private final String title;private final String version;public AppProperties(Boolean enabled, String apiKey,String title, String version) {this.enabled = enabled;this.apiKey = apiKey;this.title = title ;this.version = version ;}// 这只会有getters方法}
@ConstructorBinding 确保所有属性在对象创建期间被设置
使用 final 字段可防止初始化后被意外修改
List.copyOf() 创建允许的源列表的不可变副本
缺少 setter 方法保证了不可变性。
2.3 @EventListener 实现高级事件处理
@EventListener 的高级特性,事件驱动架构变得更加优雅:
public class OrderProcessorListener {(condition = "#event.total > 1000")(1)public void processLargeOrder(OrderCreatedEvent event) {logger.info("处理订单【{}】, 总金额: {}", event.getOrderId(), event.getTotal());// TODO}}
condition 属性根据订单金额过滤事件,只有订单总额超过1000才会被处理。
2.4 @Lazy解决循环依赖
public class CartService {private final OrderService orderService;public CartService( OrderService orderService) {this.orderService = orderService;}public void checkout(Long cartId) {// 处理结账orderService.createOrder(cartId);}}public class OrderService {private final CartService cartService;public OrderService(CartService cartService) {this.cartService = cartService;}public void cancelOrder(Long orderId) {// 恢复购物车cartService.restoreCart(orderId);}}
CartService(购物车服务)依赖于OrderService(订单服务),反之亦然。
@Lazy注解通过创建一个代理来打破这种依赖循环。
实际的OrderService bean 仅在首次被使用时才会创建。
这种模式应谨慎使用,因为循环依赖通常表明存在设计问题。
2.5 使用 @EnableConfigurationProperties 自动配置属性
@EnableConfigurationProperties({DatabaseProperties.class,CacheProperties.class})@Configurationpublic class AppConfig {@BeanDataSource dataSource(DatabaseProperties props) {return DataSourceBuilder.create().url(props.getUrl()).username(props.getUsername()).password(props.getPassword()).build();}}
@EnableConfigurationProperties 会自动注册属性类可以一次性启用多个属性类
属性会自动注入到需要它们的 bean 中
为配置管理提供了一个集中化的位置
2.6 @Profile 进行配置表达式
("prod")public DataSource prodDataSource() {return new ProductionDataSource();}("dev | test")public DataSource devDataSource() {return new EmbeddedDataSource();}
@Profile("prod") 对应 spring.profiles.active=prod
@Profile("dev | test") 对应 spring.profiles.active=dev 或 spring.profiles.active=test
它们根据配置文件中的 spring.profiles.active 属性值来决定激活哪个配置。
2.7 任务调度配置
public class SchedulingConfig {(cron = "${jobs.cleanup.schedule}")public void databaseCleanup() {// 清理逻辑}(fixedDelayString = "${jobs.health.interval}")public void healthCheck() {// 健康检查逻辑}}
这两种方法都可以在不更改代码的情况下进行配置 完美地满足了在不同环境中需要不同时间的维护任务的要求。
2.8 @Scope作用域Bean
(value = WebApplicationContext.SCOPE_REQUEST,proxyMode = ScopedProxyMode.TARGET_CLASS)public class UserContext {private User currentUser;public void setCurrentUser(User user) {this.currentUser = user;}public User getCurrentUser() {return currentUser;}}
每个HTTP请求都会创建新实例
proxyMode可确保注入单例Bean时的正确作用域隔离
非常适合在请求处理期间存储用户特定数据
请求完成后自动清理
2.9 自动重试@Retryable
public class PaymentGatewayService {(value = {TimeoutException.class},maxAttempts = 3,backoff = (delay = 1000, multiplier = 2))public PaymentResult processPayment(Payment payment) {// TODO}public PaymentResult handlePaymentFailure(TimeoutException e, Payment payment) {return PaymentResult.failed(payment.getId());}}
自动重试请求超时异常
尝试间隔采用指数退避策略(1秒、2秒、4秒)最多重试3次
@Recover方法提供回退逻辑
你需要引入如下依赖:
<dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId></dependency>
太强了!Spring Boot + JAXB 处理XML只需5行代码
Spring Boot + JavaScript 实时数据流:2种完整实现
告别OOM!Spring Boot 流式导出百万数据:支持MyBatis/JPA/Jdbc
高级开发!Spring Boot 零侵入读写分离:基于SQL解析全自动路由
Tika 与 Spring Boot 的完美结合:支持任意文档解析的神器
Spring Boot中记录JDBC、JPA及MyBatis执行SQL及参数的正确姿势
优化!高并发下 Spring Boot 乐观锁 + 悲观锁性能调优
知道太晚了!实时通信新选择fetch-event-source,真香
告别内存溢出!Spring StreamingResponseBody 三大实战案例,性能提升100%
真香!RestTemplate、RestClient再不要直接使用了,新玩法来了
技术专家!Spring AOP + Nacos + Prometheus 实现动态限流及实时监控


