公司动态
SpringBoot22-@Conditional条件装配
一、解释ConditionalConditional的作用是只有在满足某个条件时才把这个 Bean 放进 Spring 容器里。不满足条件 → 不装配满足条件 → 才装配你可以理解为if (条件满足) { 把这个 Bean 交给 Spring 管理 } else { 不要管它 }1、例子你有一个 BeanBean public UserService userService() { return new UserService(); }现在你想让这个 Bean只有在某个条件成立时才生效。加ConditionalBean Conditional(MyCondition.class) // ✅ 在某个条件成立时才注册 public UserService userService() { return new UserService(); }MyCondition是你写的“判定逻辑”类public class MyCondition implements Condition { Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 返回 true装配 // 返回 false不装配 return true; // 你可以加自己的判断逻辑 } }2、这在什么时候特别有用场景示例说明根据系统环境选择 BeanWindows vs LinuxWindows 用 A BeanLinux 用 B Bean根据配置文件开关启用功能my.feature.enabledtrue开关功能模块判断类是否存在Class.forName(...)例如自动配置第三方库时根据是否存在某个 Bean条件注入避免重复装配、冲突二、现成的条件注解Spring Boot 已经提供了很多现成的条件注解不用自己写Condition注解意义示例ConditionalOnClass某个类存在才装配缓存模块依赖 Redis 才启动ConditionalOnMissingClass某个类不存在才装配防止重复ConditionalOnBean容器里存在某 Bean 才装配依赖链ConditionalOnMissingBean容器里没有某 Bean 才装配自动配置常用ConditionalOnProperty根据配置文件值决定装配功能开关2-1、最常用ConditionalOnProperty做配置开关application.yml:my.feature.enabled: true配置类Bean ConditionalOnProperty(namemy.feature.enabled, havingValuetrue) public UserService userService() { return new UserService(); }改成false→ 这个 Bean 自动消失不用改代码只改配置非常优雅2-2、Spring Boot 自动配置为什么强因为用了大量ConditionalSpring Boot 的自动配置 ≈ Import(...) 一堆 ConditionalXxx比如 Redis 自动配置Configuration ConditionalOnClass(RedisConnection.class) // 项目里有 Redis 依赖才生效 class RedisAutoConfiguration { }如果你没引入 Redis 依赖 → 这整个配置类直接跳过。这就是为什么“你引什么依赖就自动开什么功能。”小结Conditional 带条件的 Bean满足才装不满足就跳过Spring Boot 自动配置全靠它三、Conditional 注解添加在哪里Conditional不是随便加的要加在“Spring 解析 Bean 的地方”。Conditional可以加在配置类上Configuration控制整个配置类是否生效Bean方法上控制某个 Bean 是否生效其它地方不要加它不会生效。1)加在配置类上控制一坨 BeanConfiguration Conditional(MyCondition.class) // ✅ 满足条件时这里所有 Bean 才会被注册 public class AppConfig { Bean public UserService userService(){ return new UserService(); } Bean public OrderService orderService(){ return new OrderService(); } }结果如果条件成立 →UserService和OrderService都进入容器如果条件不成立 →这个配置类整个不生效适用于开关整个功能模块2)加在Bean方法上控制单个 BeanConfiguration public class AppConfig { Bean Conditional(MyCondition.class) // ✅ 只有满足条件才创建这个 Bean public UserService userService(){ return new UserService(); } }结果满足条件 →userService注册不满足 → 不注册也就不能Autowired适用于只控制某个特定 Bean 是否装配总结Conditional 要么加在配置类 Configuration上要么加在Bean 方法上。控制模块级 → 配置类上控制单个 bean → 方法上四、举例讲解ConditionalOnBean、ConditionalOnMissingBean4-1、它们俩的本质区别注解含义什么时候装配ConditionalOnBean当容器中已经有某个 Bean 时才装配依赖存在时才生效ConditionalOnMissingBean当容器中没有某个 Bean 时才装配避免重复Bean / 提供默认实现你可以理解为ConditionalOnBean 有就装 ConditionalOnMissingBean 没有才装4-2.ConditionalOnBean示例“有依赖才启用”假设只有你项目里已经有 UserService才允许使用 OrderServiceConfiguration public class AppConfig { Bean public UserService userService() { return new UserService(); } Bean ConditionalOnBean(UserService.class) // ✅ 如果容器里存在 UserService 才创建 public OrderService orderService() { return new OrderService(); } }结果是否存在 UserServiceOrderService 是否会注册存在 ✅✅ 会装配不存在 ❌❌ 不装配适用场景比如一个功能必须依赖另一个模块才能开启。4-3.ConditionalOnMissingBean示例“没有才给你默认实现”Spring Boot 在自动配置里用得特别多。比如给你一个默认的UserService但如果你自己已经写了就不用它的Configuration public class AppConfig { // ✅ 默认 UserService Bean ConditionalOnMissingBean(UserService.class) public UserService defaultUserService(){ return new UserService(默认实现); } }用户自己写了一个Service public class UserService { public UserService() { System.out.println(这是我自己的实现); } }结果Spring Boot 发现你自己已经实现了UserService它自动跳过默认的那一个是否存在用户自定义 UserService默认实现是否会装配存在 ✅❌ 跳过默认实现不存在 ❌✅ 使用默认实现4-4、为什么 Spring Boot 自动配置很聪明因为它常常写Bean ConditionalOnMissingBean public Xxx defaultXxx(){ ... }你不写就给你默认的你一旦写了直接用你的这就解释了大家常说的Spring Boot 自动配置 → 约定优于配置自动装配是机制约定优于配置是设计思想。它们合在一起解决的是重复写样板配置的问题。约定就是框架先帮你把默认答案填好约定的本质是框架预设了一套最常用的默认行为。场景约定默认值你的选择你引入了spring-boot-starter-web约定你要用 Tomcat端口 8080不需要写任何配置就能启动你引入了mysql-connector-java约定你要连 MySQL只需要填 url/username/password你引入了spring-boot-starter-data-redis约定 Redis 在 localhost:6379不改配置就能连本地 Redis静态资源放哪约定放在classpath:/static/直接丢文件进去不用配路径优于配置的意思是约定好的默认值优先级高于你手动写的配置。只有当默认值不符合你的需求时你才需要去覆盖它。Spring Boot 用了一系列Conditional注解来实现约定判断Table注解含义约定的体现ConditionalOnClassclasspath 里有某个类才生效你引入了某个依赖我就认为你要用某个功能ConditionalOnMissingBean容器里没有这个 Bean 才生效你自己配了我就不插手ConditionalOnProperty某个配置属性存在才生效你显式开启了这个功能ConditionalOnWebApplication是 Web 应用才生效你引入了 web starter我就按 Web 应用来配这就是约定的技术实现框架通过检查你的环境classpath、配置、Bean 是否存在来猜测你需要什么然后自动配置。一句话Spring Boot 的自动装配就是框架根据你引入了什么依赖这个约定自动帮你把最可能需要的配置做完让你尽量少写甚至不写配置代码。总结ConditionalOnBean → 有它才配我 ConditionalOnMissingBean → 你没写我来补前者做依赖判断依赖存在才装配后者做默认兜底避免 Bean 冲突