接上文:springboot注解(一)
六、@Conditional
这是 Spring 4.0 添加的新注解,用来标识一个 Spring Bean 或者 Configuration 配置文件,当满足指定的条件才开启配置。它是 Spring Boot 自动配置(Auto-Configuration)机制的核心基础,实现了"按需加载"的灵活配置能力。
6.1 基本定义
java
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
- 可用于 类(@Configuration)或方法(@Bean) 上。
value指定一个或多个实现了Condition接口的类,只有当所有条件都满足时,该配置/Bean 才会被注册。
6.2 核心原理:Condition 接口
要使用 @Conditional,需实现 org.springframework.context.annotation.Condition 接口:
java
public interface Condition {
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
matches()返回true→ 条件成立,注册 Bean/配置;- 返回
false→ 跳过。
示例:自定义条件:
java
public class OnDevEnvironmentCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String env = context.getEnvironment().getProperty("app.env");
return "dev".equals(env);
}
}
@Configuration
@Conditional(OnDevEnvironmentCondition.class)
public class DevConfig {
@Bean
public MockService mockService() {
return new MockService();
}
}
只有当
app.env=dev时,DevConfig才会生效。
6.3 Spring Boot 提供的常用 @Conditional* 注解(更易用)
Spring Boot 在 @Conditional 基础上封装了一系列开箱即用的条件注解 ,无需手动实现 Condition:
| 注解 | 作用 |
|---|---|
@ConditionalOnClass |
classpath 中存在指定类时生效 |
@ConditionalOnMissingClass |
classpath 中不存在指定类时生效 |
@ConditionalOnBean |
容器中已存在指定类型的 Bean 时生效 |
@ConditionalOnMissingBean |
容器中不存在指定类型的 Bean 时生效 |
@ConditionalOnProperty |
配置文件中某属性满足条件时生效 |
@ConditionalOnWebApplication |
仅在 Web 应用中生效 |
@ConditionalOnNotWebApplication |
仅在非 Web 应用中生效 |
@ConditionalOnExpression |
SpEL 表达式为 true 时生效 |
@ConditionalOnResource |
classpath 或文件系统中存在指定资源时生效 |
示例:自动配置中的典型用法:
java
@Configuration
@ConditionalOnClass(DataSource.class) // 有 DataSource 类
@ConditionalOnMissingBean(DataSource.class) // 容器中还没有 DataSource Bean
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Bean
@ConfigurationProperties("spring.datasource")
public DataSource dataSource() {
return new HikariDataSource();
}
}
只有当项目引入了数据库驱动(如
HikariCP),且用户未自定义DataSource时,才自动配置。
6.4 使用场景
-
Starter 自动配置
Spring Boot Starter 内部大量使用
@Conditional*实现"按依赖自动装配"。 -
环境差异化配置
开发、测试、生产环境加载不同 Bean(如
@Profile本质也是基于条件)。 -
可选功能开关
通过配置属性控制某功能是否启用:
java@ConditionalOnProperty(name = "feature.email.enabled", havingValue = "true") @Bean public EmailService emailService() { ... } -
兼容多版本/多实现
根据 classpath 中存在的库选择不同实现(如 Redis 使用 Lettuce 还是 Jedis)。
6.5 注意事项
| 问题 | 说明 |
|---|---|
| 条件判断时机 | 在 Spring 容器刷新早期(BeanDefinition 注册阶段)执行,不能依赖已创建的 Bean |
| 组合条件 | 多个 @Conditional 或多个条件类是 AND 关系 ;若需 OR,需自定义 Condition |
| 与 @Profile 的关系 | @Profile("dev") 等价于 @Conditional(OnProfileCondition.class) |
| 调试技巧 | 启动时加 --debug 参数,Spring Boot 会输出自动配置报告(哪些条件匹配/不匹配) |
6.6 总结
| 特性 | 说明 |
|---|---|
| 核心作用 | 实现"按条件注册 Bean/配置" |
| 底层机制 | 基于 Condition.matches() 方法 |
| Spring Boot 增强 | 提供一系列 @ConditionalOn* 注解,极大简化使用 |
| 典型应用 | 自动配置、环境隔离、功能开关 |
| 设计思想 | "约定优于配置" + "按需加载" |
💡 一句话理解 :
@Conditional是 Spring 的"智能开关"------它让框架能根据环境、依赖、配置等上下文信息,动态决定哪些组件应该被激活,从而实现高度灵活和自动化的配置体系。
七、@ConditionalOnBean
组合 @Conditional 注解,当容器中有指定的 Bean 才开启配置。
@ConditionalOnBean 是 Spring Boot 提供的一个条件注解(Conditional Annotation) ,用于仅在 Spring 应用上下文中已存在指定类型的 Bean 时,才注册当前的 Bean 或启用某个配置类。它是构建灵活、可组合自动配置(Auto-Configuration)的关键工具之一。
7.1 基本定义
java
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {
// 指定必须存在的 Bean 的类型
Class<?>[] value() default {};
// 同 value,语义更清晰
Class<?>[] type() default {};
// 必须存在的 Bean 的注解类型(如 @Primary、@Qualifier("myBean") 等)
Class<? extends Annotation>[] annotation() default {};
// 必须存在的 Bean 的名称
String[] name() default {};
// 搜索 Bean 的容器层级(默认包括父容器)
SearchStrategy search = SearchStrategy.ALL;
}
📌 注意:
value和type是等价的,通常使用value。
7.2 核心作用
只有当 Spring 容器中已经存在满足条件的 Bean 时,被 @ConditionalOnBean 标注的配置类或 @Bean 方法才会生效。
典型使用场景:
- 在 Starter 中,只有用户提供了某个核心 Bean(如
DataSource),才自动配置相关辅助组件(如JdbcTemplate)。 - 插件式架构中,某功能模块依赖于主模块提供的服务 Bean。
7.3 使用示例
示例 1:方法级别(@Bean):
java
@Configuration
public class MyAutoConfiguration {
@Bean
@ConditionalOnBean(DataSource.class)
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
只有当容器中已有
DataSource类型的 Bean 时,才会创建JdbcTemplate。
示例 2:类级别(整个配置类):
java
@Configuration
@ConditionalOnBean(TransactionManager.class)
public class TransactionalServiceConfig {
@Bean
public OrderService orderService() {
return new OrderService();
}
@Bean
public PaymentService paymentService() {
return new PaymentService();
}
}
只有存在
TransactionManager时,才加载整个事务相关服务配置。
**示例 3:结合 name 或 annotation**:
java
@Bean
@ConditionalOnBean(name = "primaryDataSource")
public DataSourceHealthIndicator healthIndicator() {
return new DataSourceHealthIndicator();
}
或
java
@Bean
@ConditionalOnBean(annotation = Primary.class)
public CustomLogger customLogger() {
return new CustomLogger();
}
7.4 重要注意事项 ⚠️
7.4.1 Bean 注册顺序敏感
@ConditionalOnBean 判断的是当前已注册的 Bean 。如果目标 Bean 尚未被处理(例如在另一个 @Configuration 类中且加载顺序靠后),条件会失败。
✅ 最佳实践:
- 自动配置类应通过
@AutoConfigureAfter或@AutoConfigureBefore控制顺序。 - 用户自定义 Bean 通常优先于自动配置(Spring Boot 默认如此)。
7.4.2 不适用于 @Component 扫描的普通组件
@ConditionalOnBean 主要用于 @Configuration 类中的 @Bean 方法或配置类本身。
对直接标注 @Service / @Component 的类使用它通常无效,因为这些 Bean 是通过组件扫描注册的,时机和条件判断可能不匹配。
❌ 不推荐:
java@Service @ConditionalOnBean(SomeService.class) // 可能不按预期工作! public class MyService { }
7.4.3 与 @ConditionalOnMissingBean 配合使用
常用于"提供默认实现,但允许用户覆盖":
java
@Bean
@ConditionalOnMissingBean // 如果用户没定义 RedisTemplate,才用这个
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
return template;
}
7.5 与其他条件注解对比
| 注解 | 触发条件 |
|---|---|
@ConditionalOnBean |
容器中存在指定 Bean |
@ConditionalOnMissingBean |
容器中不存在指定 Bean |
@ConditionalOnClass |
classpath 中存在指定类(不关心是否是 Bean) |
@ConditionalOnProperty |
配置属性满足条件 |
7.6 总结
| 特性 | 说明 |
|---|---|
| 用途 | 条件化注册 Bean,依赖于已有 Bean 的存在 |
| 适用位置 | @Configuration 类 或 @Bean 方法 |
| 典型场景 | 自动配置、插件扩展、默认实现兜底 |
| 关键限制 | 受 Bean 加载顺序影响,慎用于普通组件类 |
| 搭配建议 | 与 @AutoConfigureAfter、@ConditionalOnMissingBean 联用 |
💡 一句话记住 :
@ConditionalOnBean就像一个"前提检查员"------它说:"只有当你已经有了 XX 服务,我才给你提供配套功能。"
八、@ConditionalOnMissingBean
组合 @Conditional 注解,和 @ConditionalOnBean 注解相反,当容器中没有指定的 Bean 才开启配置。
@ConditionalOnMissingBean 是 Spring Boot 提供的一个条件化装配注解 ,用于仅在 Spring 应用上下文中不存在指定类型的 Bean 时,才注册当前的 Bean 或启用某个配置类 。它是实现"提供默认实现,但允许用户自定义覆盖"这一设计模式的核心机制,广泛应用于 Spring Boot 的自动配置(Auto-Configuration)中。
8.1 基本定义
java
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnMissingBean {
// 指定要检查是否缺失的 Bean 类型
Class<?>[] value() default {};
// 同 value,语义更清晰
Class<?>[] type() default {};
// 检查是否缺失带有特定注解的 Bean
Class<? extends Annotation>[] annotation() default {};
// 检查是否缺失指定名称的 Bean
String[] name() default {};
// 搜索策略(是否包含父容器)
SearchStrategy search() default SearchStrategy.ALL;
// 忽略某些 Bean(通常用于排除自身)
Class<?>[] ignored() default {};
// 忽略带有特定注解的 Bean
Class<? extends Annotation>[] ignoredType() default {};
}
📌 常用属性:
value(或type)、name、annotation。
8.2 核心作用
✅ "如果你没提供,我就给你一个默认的;如果你提供了,我就用你的。"
这是 Spring Boot "约定优于配置 " 和 "开箱即用" 理念的关键体现。
8.3 典型使用场景
场景 1:自动配置中提供默认 Bean:
java
@Configuration
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(RedisTemplate.class)
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
- 如果用户没有 定义自己的
RedisTemplate,Spring Boot 自动创建一个默认的。 - 如果用户已经定义 了
RedisTemplate(例如在@Configuration类中),则跳过自动配置,使用用户的版本。
场景 2:配合 @ConditionalOnBean 实现依赖链:
java
@Bean
@ConditionalOnBean(DataSource.class) // 有 DataSource
@ConditionalOnMissingBean(JdbcTemplate.class) // 但没有 JdbcTemplate
public JdbcTemplate jdbcTemplate(DataSource ds) {
return new JdbcTemplate(ds);
}
只有当存在
DataSource且用户未提供JdbcTemplate时,才自动配置。
场景 3:排除自身(避免循环判断):
有时需要确保当前正在定义的 Bean 不被自己"误判"为已存在:
java
@Bean
@ConditionalOnMissingBean
public MyService myService() {
return new MyService();
}
等价于:
java
@Bean
@ConditionalOnMissingBean(MyService.class)
public MyService myService() {
return new MyService();
}
Spring Boot 会自动忽略当前方法返回类型的 Bean,防止"自己检查自己"。
🔍 内部原理:
OnBeanCondition会临时排除当前正在处理的 Bean 定义。
8.4 重要注意事项 ⚠️
8.4.1 Bean 加载顺序敏感
@ConditionalOnMissingBean判断的是当前已注册的 BeanDefinition。- 用户自定义的
@Bean或@Component通常先于自动配置类加载(Spring Boot 默认如此),因此能正确覆盖。 - 若自动配置类加载太早,可能误判"缺失",导致重复注册。
✅ 解决方案:
- 使用
@AutoConfigureAfter/@AutoConfigureBefore控制自动配置顺序。 - 避免在普通组件类(如
@Service)上直接使用此注解(效果不可靠)。
8.4.2 不适用于普通 @Component 类
java
// ❌ 不推荐!行为不可预测
@Service
@ConditionalOnMissingBean(SomeInterface.class)
public class MyServiceImpl implements SomeInterface { }
原因:组件扫描(
@ComponentScan)和条件判断的时机不一致,可能导致条件失效。
✅ 正确做法:在 @Configuration 类中通过 @Bean 方法定义,并加上条件注解。
8.4.3 与 @Primary、@Qualifier 的交互
-
默认按类型 匹配,若存在多个同类型 Bean,需结合
name或annotation精确控制。 -
例如:
java@Bean @ConditionalOnMissingBean(name = "customCacheManager") public CacheManager cacheManager() { ... }
8.5 与其他条件注解对比
| 注解 | 作用 |
|---|---|
@ConditionalOnMissingBean |
容器中没有指定 Bean 时生效 |
@ConditionalOnBean |
容器中有指定 Bean 时生效 |
@ConditionalOnMissingClass |
classpath 中没有指定类时生效 |
@ConditionalOnProperty |
配置属性满足条件时生效 |
8.6 调试技巧
启动应用时添加 --debug 参数,Spring Boot 会输出 自动配置报告(Auto-Configuration Report),显示:
-
哪些自动配置类被应用(
Positive matches) -
哪些被跳过及原因(
Negative matches),例如:JdbcTemplateAutoConfiguration:
Did not match:
- @ConditionalOnMissingBean (types: org.springframework.jdbc.core.JdbcTemplate; SearchStrategy: all) found beans of type 'org.springframework.jdbc.core.JdbcTemplate' (jdbcTemplate)
8.7 总结
| 特性 | 说明 |
|---|---|
| 核心目的 | 提供默认实现,支持用户自定义覆盖 |
| 典型位置 | @Configuration 类中的 @Bean 方法 |
| 关键优势 | 实现"开箱即用 + 灵活定制"的平衡 |
| 使用禁忌 | 避免用于普通 @Component 类 |
| 最佳实践 | 与自动配置机制结合,控制加载顺序 |
💡 一句话理解:
@ConditionalOnMissingBean是 Spring Boot 的"贴心备胎"------"你不用我,我不上;你没准备,我顶上。"
九、@ConditionalOnClass
组合 @Conditional 注解,当容器中有指定的 Class 才开启配置。
@ConditionalOnClass 是 Spring Boot 提供的一个条件化装配注解(Conditional Annotation) ,用于仅在类路径(classpath)中存在指定的类时,才注册某个 Bean 或启用某个配置类 。它是 Spring Boot 自动配置机制中最常用、最重要的条件注解之一,实现了"按依赖自动装配"的核心能力。
9.1 基本定义
java
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
// 指定必须存在于 classpath 中的类
Class<?>[] value() default {};
// 同 value,语义更清晰(避免与注解的 value 属性混淆)
String[] name() default {};
}
📌 通常使用
value属性传入Class对象(如DataSource.class),在无法直接引用类时(如可选依赖),可用
name传入全限定类名字符串(如"com.zaxxer.hikari.HikariDataSource")。
9.2 核心作用
✅ "只有当你引入了某个库(即 classpath 中有它的类),我才激活相关功能。"
这使得 Spring Boot 能够:
- 自动检测项目依赖;
- 按需加载对应的自动配置;
- 避免因缺少依赖而导致启动失败。
9.3 典型使用场景
9.3.1 场景 1:Starter 自动配置(最常见)
java
@Configuration
@ConditionalOnClass(DataSource.class) // classpath 中有 javax.sql.DataSource
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DataSource dataSource() {
return new HikariDataSource(); // 假设 HikariCP 也在 classpath 中
}
}
只有当项目引入了 JDBC 相关依赖(如
spring-boot-starter-jdbc),才会触发数据源自动配置。
9.3.2 场景 2:Web 应用 vs 非 Web 应用
java
@Configuration
@ConditionalOnClass(DispatcherServlet.class)
public class WebMvcAutoConfiguration {
// 注册 ViewResolver、MessageConverters 等
}
只有引入了
spring-webmvc(包含DispatcherServlet),才启用 Spring MVC 自动配置。
9.3.3 场景 3:可选依赖处理(使用 name 属性)
当某个库是可选依赖(optional dependency),不能直接引用其类(否则编译失败),可用字符串形式:
java
@Configuration
@ConditionalOnClass(name = "redis.clients.jedis.Jedis")
public class JedisAutoConfiguration {
// 配置基于 Jedis 的 Redis 客户端
}
即使项目没有引入 Jedis,也不会报错;只有引入后才激活配置。
9.4 底层原理
@ConditionalOnClass的条件由OnClassCondition实现。- 它通过 ClassLoader 检查指定类是否能被加载 (调用
Class.forName())。 - 注意 :该检查发生在 Spring 容器初始化早期(BeanDefinition 加载阶段),不涉及 Bean 实例化。
⚠️ 重要:由于它只检查 classpath 是否存在类,不要求该类被 Spring 管理为 Bean。
9.5 与其他条件注解配合使用
通常与以下注解组合,实现更精确的控制:
| 组合示例 | 说明 |
|---|---|
@ConditionalOnClass + @ConditionalOnMissingBean |
"有这个库,且你没自定义 Bean,我才配" |
@ConditionalOnClass + @ConditionalOnProperty |
"有这个库,且配置开关打开,我才配" |
@ConditionalOnClass + @AutoConfigureAfter |
控制多个自动配置的加载顺序 |
java
@Bean
@ConditionalOnClass(name = "org.springframework.security.config.annotation.web.configuration.EnableWebSecurity")
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
public WebSecurityConfigurerAdapter defaultSecurityConfig() {
// 提供默认安全配置
}
9.6 注意事项 ⚠️
9.6.1 不能用于普通组件类(如 @Service)
java
// ❌ 不推荐!可能无效
@Service
@ConditionalOnClass(SomeLibraryClass.class)
public class MyService { }
原因:组件扫描(
@ComponentScan)和条件判断时机不一致。✅ 正确做法:在
@Configuration类中通过@Bean方法定义。
9.6.2 避免循环依赖或过早加载
- 条件判断本身不会初始化类,但若在
@Bean方法中引用了该类,则会触发加载。 - 确保被检查的类无复杂的静态初始化逻辑,以免影响启动性能或引发异常。
9.6.3 调试技巧
启动时加 --debug 参数,查看自动配置报告:
DataSourceAutoConfiguration:
Matched:
- @ConditionalOnClass found required class 'javax.sql.DataSource'
或
JedisAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'redis.clients.jedis.Jedis'
9.7 总结
| 特性 | 说明 |
|---|---|
| 作用 | 根据 classpath 中是否存在类来决定是否加载配置 |
| 适用位置 | @Configuration 类 或 @Bean 方法 |
| 典型用途 | Starter 自动配置、可选依赖支持 |
| 关键优势 | 实现"依赖驱动"的自动装配,提升开箱即用体验 |
| 最佳实践 | 与 @ConditionalOnMissingBean 等组合使用,提供默认+可覆盖机制 |
💡 一句话理解:
@ConditionalOnClass是 Spring Boot 的"依赖嗅探器"------"闻到你加了某库的味道,我就悄悄把配套服务准备好。"
十、@ConditionalOnMissingClass
组合 @Conditional 注解,和 @ConditionalOnMissingClass 注解相反,当容器中没有指定的 Class 才开启配置。
@ConditionalOnMissingClass 是 Spring Boot 提供的一个条件化装配注解(Conditional Annotation) ,用于仅在类路径(classpath)中不存在指定的类时,才注册某个 Bean 或启用某个配置类 。它是 @ConditionalOnClass 的"反向"版本,常用于提供替代实现、兼容旧版本或处理可选依赖缺失的场景。
10.1 基本定义
java
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnMissingClass {
// 指定必须**不存在**于 classpath 中的类(全限定名)
String[] value() default {};
}
📌 注意:
- 只接受 字符串形式的全限定类名 (如
"com.example.SomeClass"),不支持 Class<?> 类型。 - 这是为了避免在编译期强制依赖该类(否则如果类不存在,项目无法编译)
10.2 核心作用
✅ "只有当你没有引入某个库(即 classpath 中缺少它的类),我才激活这个备用方案。"
典型用途包括:
- 提供轻量级替代实现;
- 兼容不同技术栈(如 Jedis vs Lettuce);
- 在缺少高级功能库时降级到基础实现。
10.3 典型使用场景
场景 1:提供默认/轻量级实现(当高级库未引入时):
java
// 如果用户没有引入 HikariCP,则使用 Tomcat JDBC Pool(较老但内嵌)
@Configuration
@ConditionalOnMissingClass("com.zaxxer.hikari.HikariDataSource")
public class TomcatJdbcDataSourceConfiguration {
@Bean
@ConditionalOnMissingBean(DataSource.class)
public DataSource dataSource() {
return new org.apache.tomcat.jdbc.pool.DataSource();
}
}
💡 Spring Boot 实际正是这样设计的:优先尝试高性能连接池(如 Hikari),若未引入则回退到其他实现。
场景 2:兼容不同 Redis 客户端:
java
// 如果没有使用 Lettuce,则启用 Jedis 配置
@Configuration
@ConditionalOnClass(name = "redis.clients.jedis.Jedis") // 确保 Jedis 可用
@ConditionalOnMissingClass("io.lettuce.core.RedisClient") // 且 Lettuce 未引入
public class JedisRedisAutoConfiguration {
// 配置 Jedis
}
这样可以确保:Lettuce 优先,Jedis 作为备选。
场景 3:降级到无依赖实现:
java
// 如果没有引入邮件库,则提供一个空实现(避免启动失败)
@Configuration
@ConditionalOnMissingClass("org.springframework.mail.javamail.JavaMailSender")
public class NoOpMailConfiguration {
@Bean
public JavaMailSender javaMailSender() {
return new NoOpJavaMailSender(); // 自定义空实现
}
}
适用于可选功能模块,保证核心功能不受影响。
10.4 底层原理
- 与
@ConditionalOnClass共享同一个条件类:OnClassCondition。 - 内部通过
ClassLoader.loadClass()尝试加载指定类名:- 若 抛出 ClassNotFoundException → 条件成立(类缺失);
- 若 成功加载 → 条件不成立。
⚠️ 注意:该检查发生在 Spring 容器初始化早期,不会触发类的初始化(static 块等)。
10.5 重要注意事项 ⚠️
10.5.1 只能使用字符串类名
java
// ✅ 正确
@ConditionalOnMissingClass("com.zaxxer.hikari.HikariDataSource")
// ❌ 编译错误!不支持 Class 对象
@ConditionalOnMissingClass(HikariDataSource.class)
10.5.2 不适用于普通组件类(如 @Service)
java
// ❌ 不推荐
@Service
@ConditionalOnMissingClass("some.OptionalLib")
public class MyService { }
原因:组件扫描时机与条件判断不匹配,可能导致行为不可预测。
✅ 正确做法:在
@Configuration类中通过@Bean方法定义。
10.5.3 慎用于关键路径
- 如果条件判断错误(如类名拼写错误),可能导致预期功能未加载,引发运行时问题。
- 建议配合
--debug启动参数验证自动配置是否按预期匹配。
10.6 与其他条件注解对比
| 注解 | 触发条件 |
|---|---|
@ConditionalOnClass |
classpath 存在指定类 |
@ConditionalOnMissingClass |
classpath 不存在指定类 |
@ConditionalOnBean |
容器中存在指定 Bean |
@ConditionalOnMissingBean |
容器中不存在指定 Bean |
10.7 调试技巧
启动应用时添加 --debug 参数,查看自动配置报告:
text
TomcatJdbcDataSourceConfiguration:
Matched:
- @ConditionalOnMissingClass did not find required class 'com.zaxxer.hikari.HikariDataSource'
HikariDataSourceConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'com.zaxxer.hikari.HikariDataSource'
10.8 总结
| 特性 | 说明 |
|---|---|
| 作用 | 根据 classpath 中缺失某类来决定是否加载配置 |
| 参数类型 | 仅支持全限定类名字符串(String[]) |
| 典型用途 | 降级实现、备选方案、兼容性处理 |
| 使用位置 | @Configuration 类 或 @Bean 方法 |
| 最佳实践 | 与 @ConditionalOnClass 配合,实现"优先 A,否则 B"的策略 |
💡 一句话理解:
@ConditionalOnMissingClass是 Spring Boot 的"Plan B 触发器"------
"你没带伞?那我给你一件雨衣。"
10.9 上面说的classpath指的是什么
在 Java 和 Spring Boot 的上下文中,classpath(类路径) 指的就是 JVM 在运行时用来查找和加载 .class 文件(以及资源文件)的所有路径集合 ,它包括你项目中引入的所有依赖(JAR 包)、你自己编译的类、以及配置资源等。
10.9.1 具体来说,classpath 包含哪些内容?
- 你项目的源代码编译后的 .class 文件
- 例如:
target/classes(Maven)或build/classes/java/main(Gradle)目录下的类。 - 这些是你自己写的
@Service、@Controller、工具类等。
-
你通过构建工具引入的所有依赖(JAR 包)
-
比如你在
pom.xml或build.gradle中声明的:x'm<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>Maven/Gradle 会把这些 JAR 下载到本地仓库,并在运行时加入 classpath。 -
Maven/Gradle 会把这些 JAR 下载到本地仓库,并在运行时加入 classpath。
-
每个 JAR 内部也包含自己的
.class文件(如DispatcherServlet.class、DataSource.class等)。
- 资源文件目录
-
- 如
src/main/resources下的application.properties、static/、templates/等。 - 虽然这些不是
.class文件,但也在 classpath 中,可通过ClassLoader.getResource()访问。
- JDK 自带的核心类库
- 如
java.lang.String、java.util.ArrayList等,由 Bootstrap ClassLoader 加载,也属于广义 classpath 的一部分(但通常不参与 Spring 的条件判断)。
10.9.2 总结
| 问题 | 回答 |
|---|---|
| classpath 是什么? | JVM 加载类和资源的路径集合 |
| 包含我引入的包吗? | ✅ 是的,所有依赖 JAR 都在其中 |
| 包含我自己写的类吗? | ✅ 是的,编译后的 .class 文件也在 |
| Spring 条件注解检查的是它吗? | ✅ 正是!@ConditionalOnClass 就是检查这个 |
| 和操作系统路径有关吗? | ❌ 无关,它是 Java 虚拟机层面的概念 |