衡阳市网站建设_网站建设公司_PHP_seo优化
2026/1/7 7:25:03 网站建设 项目流程

十一、@ConditionalOnWebApplication

组合 @Conditional 注解,当前项目类型是 WEB 项目才开启配置。

当前项目有以下 3 种类型。

@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documented@Conditional({OnWebApplicationCondition.class})public@interfaceConditionalOnWebApplication{Typetype()defaultConditionalOnWebApplication.Type.ANY;publicstaticenumType{ANY,SERVLET,REACTIVE;privateType(){}}}

11.1 作用

该注解的作用是:只有当 Spring 应用上下文是一个 Web 应用上下文时,被注解的类或方法才会被注册为 Bean 或生效。

这在自动配置(Auto-Configuration)中非常常见,用于区分 Web 应用和非 Web 应用(如批处理、命令行工具等)。

11.2 使用方式

11.2.1 注解在类上(通常用于@Configuration类)

@Configuration@ConditionalOnWebApplicationpublicclassWebConfig{// 只有在 Web 应用中才会加载这个配置类}

11.2.2 注解在@Bean方法上

@Bean@ConditionalOnWebApplicationpublicMyWebBeanmyWebBean(){returnnewMyWebBean();}

11.3 可选类型(type 属性)

从 Spring Boot 2.0 开始,@ConditionalOnWebApplication支持通过type属性进一步指定 Web 应用的类型:

@ConditionalOnWebApplication(type=Type.SERVLET)// 或@ConditionalOnWebApplication(type=Type.REACTIVE)

其中Type枚举包括:

  • Type.SERVLET:基于 Servlet 的 Web 应用(如使用 Tomcat、Jetty)
  • Type.REACTIVE:响应式 Web 应用(如使用 WebFlux + Netty)
  • Type.ANY(默认值):只要是 Web 应用(Servlet 或 Reactive 都算)

注意:如果不指定type,默认是Type.ANY

11.4 判断依据

Spring Boot 判断是否为 Web 应用的标准是:

  • 是否存在WebApplicationContext(即是否使用了 Web 相关的 ApplicationContext 实现)
  • 对于 Servlet 应用:是否存在DispatcherServletServletContext
  • 对于 Reactive 应用:是否存在ReactiveWebApplicationContext

11.5 典型应用场景

  • 自动配置 Web 相关的过滤器、拦截器、控制器等
  • 避免在非 Web 应用(如 Spring Boot CLI 工具、批处理任务)中加载不必要的 Web 组件
  • 区分 Servlet 和 Reactive 环境,提供不同的实现

11.6 示例:区分 Servlet 与 Reactive

@Configuration@ConditionalOnWebApplication(type=Type.SERVLET)publicclassServletWebConfig{// 仅在 Servlet 环境下生效}@Configuration@ConditionalOnWebApplication(type=Type.REACTIVE)publicclassReactiveWebConfig{// 仅在 Reactive 环境下生效}

11.7 总结

@ConditionalOnWebApplication是 Spring Boot 条件化配置的重要工具之一,能帮助开发者根据应用类型动态启用或禁用某些配置,从而提升模块的通用性和灵活性。

十二、@ConditionalOnNotWebApplication

组合 @Conditional 注解,和 @ConditionalOnWebApplication 注解相反,当前项目类型不是 WEB 项目才开启配置。

12.1 作用

该注解用于仅在当前应用不是一个 Web 应用时,才加载被注解的配置类、Bean 或组件。

换句话说:
只有当应用是“非 Web 应用”(如命令行工具、批处理任务、后台服务等)时,该配置才会生效。

12.2 使用方式

12.2.1 注解在配置类上

@Configuration@ConditionalOnNotWebApplicationpublicclassBatchConfig{// 仅在非 Web 应用中加载此配置}

12.2.2 注解在@Bean方法上

@Bean@ConditionalOnNotWebApplicationpublicTaskRunnertaskRunner(){returnnewCommandLineTaskRunner();}

12.3 判断逻辑

Spring Boot 判断“是否为非 Web 应用”的依据是:

  • 应用上下文不是WebApplicationContext的子类型;
  • 没有启动内嵌 Web 容器(如 Tomcat、Jetty、Netty);
  • 没有引入 Web 相关依赖(如spring-boot-starter-webspring-boot-starter-webflux),或者虽引入但未激活 Web 环境(例如通过SpringApplication.setWebApplicationType(WebApplicationType.NONE)显式关闭)。

注意:只要应用被识别为Servlet WebReactive Web应用,@ConditionalOnNotWebApplication不会生效

12.4 典型应用场景

  • 命令行应用(CLI 工具)

你开发了一个数据迁移工具,只在命令行运行,不需要 Web 服务器:

@SpringBootApplicationpublicclassDataMigrator{publicstaticvoidmain(String[]args){SpringApplicationapp=newSpringApplication(DataMigrator.class);app.setWebApplicationType(WebApplicationType.NONE);// 显式设为非 Webapp.run(args);}}
  • 批处理任务(Spring Batch)
    在非 Web 环境中启用批处理作业配置。
  • 避免 Web 组件污染非 Web 上下文
    防止 Web 相关的 Bean(如 Controller、Filter)被错误加载到纯后台服务中。

12.5 与@ConditionalOnWebApplication的关系

注解生效条件
@ConditionalOnWebApplication应用是 Web 应用(Servlet 或 Reactive)
@ConditionalOnNotWebApplication应用不是Web 应用(即WebApplicationType.NONE

二者互斥,常用于提供不同运行环境下的差异化配置

12.6 注意事项

  • 从 Spring Boot 2.0 起,该注解不再支持 type 属性(因为“非 Web”本身就是一种明确状态,无需细分)。
  • 如果你的项目同时包含 Web 和非 Web 模块,合理使用此注解可避免 Bean 冲突或不必要的资源加载。

总结

@ConditionalOnNotWebApplication是 Spring Boot 条件装配体系中的重要一环,专为非 Web 应用场景设计,确保配置和组件只在合适的环境中激活,提升应用的模块化与健壮性。

十三、@ConditionalOnProperty

组合 @Conditional 注解,当指定的属性有指定的值时才开启配置。

@ConditionalOnProperty是 Spring Boot 提供的一个条件注解(Conditional Annotation),用于根据配置属性(application.properties 或 application.yml 中的属性)的值来决定是否加载某个 Bean、配置类或组件。

13.1 核心作用

只有当指定的配置属性存在,并且其值满足特定条件时,被注解的类或方法才会生效。

这是实现“按需启用功能”(如开关控制、环境差异化配置)的常用手段。

13.2 基本用法

1.最简形式:检查属性是否存在(不关心值)

@ConditionalOnProperty("my.feature.enabled")

只要my.feature.enabled在配置文件中有定义(无论值是truefalse1"hello"等),条件就成立。

⚠️ 注意:如果属性未定义(即完全不存在),条件不成立

1.检查属性值是否等于指定值

@ConditionalOnProperty(name="my.feature.enabled",havingValue="true")

只有当my.feature.enabled=true时才生效(默认havingValue = "",但通常配合使用)。

3.支持多个属性(逻辑 AND)

@ConditionalOnProperty( prefix = "my.service", name = {"host", "port"}, matchIfMissing = false )

表示my.service.hostmy.service.port都必须存在(且值非空)才生效。

❗ 多个属性之间是AND 关系,不能直接表达 OR 逻辑(需自定义 Condition)。

13.3 常用属性详解

属性说明
name/value要检查的属性名(支持数组,多个属性需同时满足)
prefix属性前缀,与name拼接使用(如prefix="app.db", name="url"app.db.url
havingValue期望的属性值(默认为空字符串)。若设置,则属性值必须完全匹配(区分大小写)
matchIfMissing当属性未定义时是否匹配,默认false。设为true可实现“默认开启”

13.4 典型示例

✅ 示例 1:功能开关
# application.properties app.cache.enabled=true
@Configuration@ConditionalOnProperty(name="app.cache.enabled",havingValue="true")publicclassCacheConfig{@BeanpublicCacheManagercacheManager(){returnnewRedisCacheManager();}}

只有当app.cache.enabled=true时,才加载缓存配置。

✅ 示例 2:默认启用(matchIfMissing = true
@ConditionalOnProperty(name="app.metrics.enabled",havingValue="true",matchIfMissing=true// 如果没配置,默认视为 true)publicclassMetricsAutoConfiguration{// ...}
  • 若配置了app.metrics.enabled=false→ 不加载
  • 若未配置该属性 →加载(因为matchIfMissing = true

常用于“默认开启,可关闭”的场景。

✅ 示例 3:检查多个属性
# application.ymlmy:datasource:url:jdbc:mysql://...username:root
@ConditionalOnProperty(prefix="my.datasource",name={"url","username"})publicclassCustomDataSourceConfig{// 仅当 url 和 username 都配置了才生效}

13.5 注意事项

  1. 值匹配是字符串精确匹配
    havingValue = "true"不会把"TRUE"1视为 true,必须是字面量"true"
  2. 布尔属性的常见陷阱
    Spring Boot 会自动将true/false解析为布尔值,但在条件判断中仍按字符串处理
feature.x=true # 实际传入 Condition 的是字符串 "true"

所以havingValue = "true"是安全的。

  1. 不支持 OR 条件
    如需“propA=xxxpropB=yyy”,需自定义@Conditional+Condition实现。
  2. 优先级
    条件判断基于最终生效的配置(包括@PropertySource、环境变量、命令行参数等)。

13.6 底层原理

@ConditionalOnProperty基于 Spring 的@Conditional机制,内部使用OnPropertyCondition类进行判断。它会从Environment中读取属性值并进行匹配。


13.7 总结

@ConditionalOnProperty是 Spring Boot外部化配置 + 条件装配的核心注解之一,适用于:

  • 功能开关(Feature Toggle)
  • 环境差异化配置(dev/test/prod)
  • 可选模块的自动装配(如监控、日志增强等)

通过灵活组合namehavingValuematchIfMissing,可以实现强大而清晰的配置驱动行为。

十四、@ConditionalOnExpression

组合 @Conditional 注解,当 SpEL 表达式为 true 时才开启配置。

@ConditionalOnExpression是 Spring Boot(基于 Spring Framework 的条件机制)提供的一个条件注解(Conditional Annotation),它允许你使用SpEL(Spring Expression Language)表达式来动态决定某个配置类、Bean 或组件是否应该被加载。

14.1 核心作用

只有当指定的 SpEL 表达式计算结果为 true 时,被注解的类或方法才会生效。

这使得你可以基于任意复杂的逻辑(如多个配置属性组合、系统属性、环境变量、甚至 Bean 状态)来控制配置的启用。

14.2 基本语法

@ConditionalOnExpression("#{spel表达式}")
  • 表达式必须放在#{...}中(这是 SpEL 的标准语法)。
  • 表达式最终需返回一个布尔值(boolean)
  • 如果表达式求值为true→ 条件成立,Bean/配置生效;否则不生效。

14.3 常用场景与示例

✅ 示例 1:基于单个配置属性
# application.properties app.feature.enabled=true
@Configuration@ConditionalOnExpression("${app.feature.enabled:false}")publicclassFeatureConfig{// 当 app.feature.enabled 为 true 时加载}

注意:这里${...}是属性占位符,会被替换为实际值,然后作为布尔表达式求值。

✅ 示例 2:组合多个属性(AND / OR)
app.mode=dev app.debug=true
// 只有在 dev 模式且 debug 开启时才生效@ConditionalOnExpression("${app.mode} == 'dev' and ${app.debug:true}")publicclassDevToolsConfig{}

或者使用 OR:

// dev 或 test 环境都启用@ConditionalOnExpression("'${app.env}' == 'dev' or '${app.env}' == 'test'")publicclassTestSupportConfig{}
✅ 示例 3:结合系统属性或环境变量
// 当系统属性 enable.metrics 为 true 时启用@ConditionalOnExpression("#{systemProperties['enable.metrics'] == 'true'}")publicclassMetricsConfig{}// 或检查环境变量@ConditionalOnExpression("#{environment['ENABLE_LOGGING'] == 'true'}")publicclassLoggingEnhancer{}
  • systemProperties:Java 系统属性(如-Denable.metrics=true
  • environment:操作系统环境变量或 Spring Environment 中的所有属性
✅ 示例 4:更复杂的逻辑(字符串判断、非空等)
// 当 my.service.url 非空且以 https 开头@ConditionalOnExpression("'${my.service.url:}'.startsWith('https')")publicclassSecureServiceClient{}

使用${prop:default}提供默认值(避免属性未定义时报错)。

14.4 注意事项

  1. 表达式必须返回布尔值
    如果表达式返回非布尔类型(如字符串、数字),Spring 会尝试转换,但容易出错。建议显式写成布尔逻辑。
  2. 属性未定义时可能抛异常
    如果直接写${some.prop}而该属性不存在,会抛IllegalArgumentException
    解决方法:提供默认值,如${some.prop:false}${some.prop:}
  3. 性能影响极小
    表达式只在应用启动时求值一次,不影响运行时性能。
  4. 调试困难
    复杂表达式难以调试。建议保持简洁,或封装到自定义Condition中。
  5. 优先级低于 @Profile
    如果同时使用@Profile@ConditionalOnExpression,两者需同时满足。

14.5 与@ConditionalOnProperty的对比

特性@ConditionalOnProperty@ConditionalOnExpression
灵活性低(仅支持属性存在性/值匹配)高(支持任意 SpEL 表达式)
可读性高(语义清晰)中(复杂表达式难读)
安全性高(自动处理属性缺失)低(需手动处理默认值)
适用场景简单开关、属性匹配多属性组合、环境判断、复杂逻辑

✅ 建议:优先使用 @ConditionalOnProperty,仅在需要复杂逻辑时用@ConditionalOnExpression

14.5 底层原理

@ConditionalOnExpression基于 Spring 的@Conditional机制,内部使用OnExpressionCondition类。它通过StandardEvaluationContext解析 SpEL 表达式,并注入了以下变量:

  • environment:当前Environment
  • systemPropertiesSystem.getProperties()
  • systemEnvironmentSystem.getenv()

14.6 总结

@ConditionalOnExpression是 Spring Boot 中最灵活的条件注解之一,适用于需要动态、组合、环境感知的配置控制场景。但因其表达式复杂性和潜在的运行时错误,应谨慎使用,保持表达式简洁,并做好默认值处理。

十五、@ConditionalOnJava

组合 @Conditional 注解,当运行的 Java JVM 在指定的版本范围时才开启配置。

@ConditionalOnJava是 Spring Boot 提供的一个条件注解(Conditional Annotation),用于根据当前运行的 Java 版本来决定是否加载某个配置类、Bean 或自动配置组件。

15.1 核心作用

只有当 JVM 的 Java 版本满足指定条件(如等于、高于或低于某个版本)时,被注解的类或方法才会生效。

这在需要兼容多个 Java 版本、或利用高版本 Java 特性(如模块系统、新 API)时非常有用。

15.2 基本用法

@ConditionalOnJava(JavaVersion.ELEVEN)

表示:仅在 Java 11 环境下生效

更常见的用法是指定范围

@ConditionalOnJava(range=Range.OLDER_THAN,value=JavaVersion.ELEVEN)// 表示:Java 版本 < 11 时生效@ConditionalOnJava(range=Range.AT_LEAST,value=JavaVersion.SIXTEEN)// 表示:Java 版本 >= 16 时生效

15.3 关键属性说明

属性类型说明
valueJavaVersion目标 Java 版本(必需)
rangeRange枚举比较方式,默认为Range.EQUAL_OR_NEWER(即 ≥)
JavaVersion支持的版本(截至 Spring Boot 3.x):
  • SIX,SEVEN,EIGHT,NINE,TEN,ELEVEN,TWELVE, …,TWENTY_ONE
  • 也支持通过JavaVersion.valueOf("17")动态解析

⚠️ 注意:Spring Boot 3.x 要求最低 Java 17,因此低版本(如 Java 8)的条件在 SB3 中通常不会命中。

Range枚举值:
含义
EQUAL_OR_NEWER≥(默认)
OLDER_THAN<
ACCEPTED==(精确匹配,但实际比较逻辑是“主版本号相等”)

📌 实际比较基于Java 主版本号(Major Version),例如17.0.2→ 主版本为17

15.4 典型使用场景

✅ 场景 1:为不同 Java 版本提供不同实现
// Java 8~10 使用传统实现@Bean@ConditionalOnJava(range=Range.OLDER_THAN,value=JavaVersion.ELEVEN)publicMyServicemyServiceLegacy(){returnnewLegacyMyService();}// Java 11+ 使用新特性(如 HttpClient)@Bean@ConditionalOnJava(range=Range.AT_LEAST,value=JavaVersion.ELEVEN)publicMyServicemyServiceModern(){returnnewModernMyService();}
✅ 场景 2:禁用不兼容高版本 Java 的旧功能
@Configuration@ConditionalOnJava(range=Range.OLDER_THAN,value=JavaVersion.SEVENTEEN)publicclassLegacySecurityConfig{// 仅在 Java < 17 时加载(因 Java 17 移除了某些加密算法)}
✅ 场景 3:Spring Boot 自动配置中的兼容处理

Spring Boot 内部大量使用此注解,例如:

  • 在 Java 9+ 启用模块路径相关配置
  • 在 Java 14+ 启用 Record 支持(未来可能)

15.5 注意事项

  1. 版本检测基于运行时 JVM
    与编译版本无关,只看java -version的实际运行环境。
  2. 主版本号比较
    JavaVersion.ELEVEN对应主版本1111.0.1211.0.2都视为11
  3. Spring Boot 版本限制
    • Spring Boot 2.x:支持 Java 8 ~ 19
    • Spring Boot 3.x:最低要求 Java 17,因此@ConditionalOnJava(value = JavaVersion.EIGHT)在 SB3 中永远不会生效。
  4. 不支持补丁版本精细控制
    无法判断17.0.1vs17.0.2,仅支持主版本(如 17、18、19…)。

15.6 底层原理

@ConditionalOnJava基于@Conditional(OnJavaCondition.class)实现。
OnJavaCondition会:

  1. 获取当前 JVM 版本(通过System.getProperty("java.version")
  2. 解析为主版本号(如"17.0.5" → 17
  3. value指定的版本按range进行比较

15.7 替代方案(手动判断)

如果需要更灵活的版本判断(如检查是否 ≥ Java 17 且 < Java 21),可结合@ConditionalOnExpression

@ConditionalOnExpression("#{T(java.lang.Runtime).version().feature() >= 17 && "+" T(java.lang.Runtime).version().feature() < 21}")

使用Runtime.version()(Java 9+ 引入)可获取精确版本信息。

15.8 总结

@ConditionalOnJava是 Spring Boot 中用于Java 版本兼容性控制的重要工具,适用于:

  • 多版本 Java 环境下的差异化配置
  • 利用高版本 Java 新特性
  • 规避旧版 JVM 的限制或安全问题

合理使用它,可以让你的库或应用在不同 Java 环境中安全、高效、自动适配

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询