springboot注解(二)

接上文: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 使用场景

  1. Starter 自动配置

    Spring Boot Starter 内部大量使用 @Conditional* 实现"按依赖自动装配"。

  2. 环境差异化配置

    开发、测试、生产环境加载不同 Bean(如 @Profile 本质也是基于条件)。

  3. 可选功能开关

    通过配置属性控制某功能是否启用:

    java 复制代码
    @ConditionalOnProperty(name = "feature.email.enabled", havingValue = "true")
    @Bean
    public EmailService emailService() { ... }
  4. 兼容多版本/多实现

    根据 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;
}

📌 注意:valuetype 是等价的,通常使用 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:结合 nameannotation**

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)、nameannotation

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,需结合 nameannotation 精确控制。

  • 例如:

    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 包含哪些内容?

  1. 你项目的源代码编译后的 .class 文件
  • 例如:target/classes(Maven)或 build/classes/java/main(Gradle)目录下的类。
  • 这些是你自己写的 @Service@Controller、工具类等。
  1. 你通过构建工具引入的所有依赖(JAR 包)

    • 比如你在 pom.xmlbuild.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.classDataSource.class 等)。

    1. 资源文件目录
  • src/main/resources 下的 application.propertiesstatic/templates/ 等。
  • 虽然这些不是 .class 文件,但也在 classpath 中,可通过 ClassLoader.getResource() 访问。
  1. JDK 自带的核心类库
  • java.lang.Stringjava.util.ArrayList 等,由 Bootstrap ClassLoader 加载,也属于广义 classpath 的一部分(但通常不参与 Spring 的条件判断)。

10.9.2 总结

问题 回答
classpath 是什么? JVM 加载类和资源的路径集合
包含我引入的包吗? ✅ 是的,所有依赖 JAR 都在其中
包含我自己写的类吗? ✅ 是的,编译后的 .class 文件也在
Spring 条件注解检查的是它吗? ✅ 正是!@ConditionalOnClass 就是检查这个
和操作系统路径有关吗? ❌ 无关,它是 Java 虚拟机层面的概念
相关推荐
神奇小汤圆1 天前
MyBatis批量插入从5分钟优化到3秒,我做了这3件事
后端
上去我就QWER1 天前
什么是反向代理?
后端·nginx
Cosmoshhhyyy1 天前
《Effective Java》解读第32条:谨慎并用泛型和可变参数
java·python
帅气的你1 天前
面向Java程序员的思维链(CoT)提示词写法学习指南
java
Charlo1 天前
手把手配置 Ralph -- 火爆 X 的全自动 AI 编程工具
前端·后端·github
一只小小Java1 天前
Java面试场景高频题
java·开发语言·面试
沛沛老爹1 天前
Web开发者快速上手AI Agent:基于Function Calling的12306自动订票系统实战
java·人工智能·agent·web转型
CRUD酱1 天前
后端使用POI解析.xlsx文件(附源码)
java·后端
亓才孓1 天前
多态:编译时看左边,运行时看右边
java·开发语言