Liquibase Maven插件执行级expressionVars未继承全局属性问题
问题场景
使用liquibase-maven-plugin 4.7.1,在插件全局配置中定义了expressionVars的prop1和prop2两个属性,用于替换changelog(含被引入的子changelog)中的占位符,全局配置下所有execution生成SQL都正常。
但在某一个execution中,仅想覆盖prop1为特定值,期望prop2保留全局配置的值。于是在该execution的configuration中只配置了prop1的特定值,结果生成的SQL里prop1被正确替换,但${prop2}占位符完全没被替换。
执行mvn help:effective-pom查看,该execution的配置里同时存在prop1的特定值和prop2的全局值,符合预期,但实际运行时还是出现prop2未替换的问题。
相关配置
原始POM配置
<plugin> <groupId>org.liquibase</groupId> <artifactId>liquibase-maven-plugin</artifactId> <version>4.7.1</version> <configuration> <outputFileEncoding>UTF-8</outputFileEncoding> <expressionVars> <property> <name>prop1</name> <value>some-common-value-1</value> </property> <property> <name>prop2</name> <value>some-common-value-2</value> </property> </expressionVars> </configuration> <executions> ... <execution> <id>one</id> <phase>generate-resources</phase> <goals> <goal>updateSQL</goal> </goals> <configuration> <changeLogFile>some-changelog.xml</changeLogFile> <url>...</url> <migrationSqlOutputFile>file.sql</migrationSqlOutputFile> <expressionVars> <property> <name>prop1</name> <value>some-specific-value-1</value> </property> </expressionVars> </configuration> </execution> .... </plugin>
生效后的POM(mvn help:effective-pom输出)
<configuration> <changeLogFile>some-changelog.xml</changeLogFile> <url>...</url> <migrationSqlOutputFile>file.sql</migrationSqlOutputFile> <expressionVars> <property> <name>prop1</name> <value>some-specific-value-1</value> </property> <property> <name>prop2</name> <value>some-common-value-2</value> </property> </expressionVars> </configuration>
问题原因
这是Liquibase Maven插件4.7.1及更早版本的已知bug:虽然Maven会正确合并全局与execution的expressionVars配置(所以effective POM显示正常),但Liquibase插件内部的配置读取逻辑存在问题,当execution中重新定义expressionVars节点时,插件会直接覆盖整个属性集合,而非合并全局属性,导致全局配置的prop2实际未被加载。
解决方案
方案1:显式重复全局属性(快速临时解决)
在目标execution的expressionVars中同时写上prop2的全局值,虽然冗余但能确保两个属性都被加载:
<execution> <id>one</id> <phase>generate-resources</phase> <goals> <goal>updateSQL</goal> </goals> <configuration> <changeLogFile>some-changelog.xml</changeLogFile> <url>...</url> <migrationSqlOutputFile>file.sql</migrationSqlOutputFile> <expressionVars> <property> <name>prop1</name> <value>some-specific-value-1</value> </property> <property> <name>prop2</name> <value>some-common-value-2</value> </property> </expressionVars> </configuration> </execution>
方案2:升级插件版本(根治问题)
将liquibase-maven-plugin升级到4.8.0及以上版本,该版本修复了expressionVars的合并逻辑问题,升级后无需修改现有配置即可正常合并全局与execution的属性。
方案3:改用Maven全局属性传递(更优雅的方式)
将prop1和prop2定义为Maven全局属性,在插件的expressionVars中引用这些属性,这样在execution中只需覆盖对应的Maven属性,无需重新定义expressionVars:
- 定义Maven全局属性:
<properties> <liquibase.prop1>some-common-value-1</liquibase.prop1> <liquibase.prop2>some-common-value-2</liquibase.prop2> </properties>
- 插件全局配置引用Maven属性:
<plugin> <groupId>org.liquibase</groupId> <artifactId>liquibase-maven-plugin</artifactId> <version>4.7.1</version> <configuration> <outputFileEncoding>UTF-8</outputFileEncoding> <expressionVars> <property> <name>prop1</name> <value>${liquibase.prop1}</value> </property> <property> <name>prop2</name> <value>${liquibase.prop2}</value> </property> </expressionVars> </configuration> <executions> ... <execution> <id>one</id> <phase>generate-resources</phase> <goals> <goal>updateSQL</goal> </goals> <configuration> <changeLogFile>some-changelog.xml</changeLogFile> <url>...</url> <migrationSqlOutputFile>file.sql</migrationSqlOutputFile> <!-- 仅覆盖Maven属性,无需修改expressionVars --> <properties> <liquibase.prop1>some-specific-value-1</liquibase.prop1> </properties> </configuration> </execution> .... </plugin>
内容的提问来源于stack exchange,提问作者wi2ard

