Spring Boot 2.1.0 和 Flyway 4.2.0
Posted
技术标签:
【中文标题】Spring Boot 2.1.0 和 Flyway 4.2.0【英文标题】:Spring Boot 2.1.0 with Flyway 4.2.0 【发布时间】:2019-04-19 23:24:48 【问题描述】:我想将我的新项目升级到 Spring Boot 版本 2.1.0,但我受限于 Oracle 11 数据库,Flyway 4.2.0 库支持该数据库。一切都在 Spring Boot 2.0.5 版本上正常运行,但是当移动到 2.1.0 版本时,我收到此错误:
java.lang.NoClassDefFoundError:
org/flywaydb/core/api/configuration/FluentConfiguration
POM配置如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<ojdbc6.version>11.2.0.1</ojdbc6.version>
</properties>
<dependencies>
<dependency>
<groupId>com.oracle.jdbc</groupId>
<artifactId>ojdbc6</artifactId>
<version>$ojdbc6.version</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>4.2.0</version>
</dependency>
</dependencies>
更新
我可以通过@Configuration 解决问题(或者当然添加到主类),但问题是它的错误还是功能?在 2.1.0 版本之前,一切都是通过自动配置完成的,并且开箱即用。
@Bean(initMethod = "migrate")
Flyway flyway()
Flyway flyway = new Flyway();
flyway.setBaselineOnMigrate(true);
flyway.setDataSource("jdbc:oracle:thin:@localhost:1521:xe", "USER", "PASSWORD1");
return flyway;
【问题讨论】:
这根本不是错误。 Spring Boot 依赖于 Flyway 5.2.1,它的 API 与您使用的旧版本不同。 是的,我注意到了,但不能以某种方式将它排除在 pom.xml 中以支持旧版本吗?我可以找到正确的依赖项,但它正在寻找这个 FluentConfiguration 类。 当然可以。但这不会改变配置 Flyway 的 Spring Boot 代码,它使用仅存在于最新版本 Flyway 中的新类。打个比方,如果你用 Java 8 编译使用 java.util.stream 的类,然后尝试在 Java 7 上运行该代码,那是行不通的,因为 Java 7 中不存在 java.util.stream . 您是如何测试您的应用的? 【参考方案1】:我在 PostgreSQL 9.2 也遇到了同样的问题,使用下面的类解决了这个问题。
请注意,您可能在 Spring Boot 属性中设置的所有自定义属性都将被忽略,因为这会用您自己的方式替换整个 Flyway 自动配置。因此,您可能需要添加一些额外的代码以满足您的需求。
@Configuration
class FlywayConfig
@Bean
fun flyway(dataSource: DataSource): Flyway
val flyway = Flyway()
flyway.dataSource = dataSource
return flyway
@Bean
fun flywayInitializer(flyway: Flyway): FlywayMigrationInitializer
return FlywayMigrationInitializer(flyway, null)
/**
* Additional configuration to ensure that [EntityManagerFactory] beans depend on the
* `flywayInitializer` bean.
*/
@Configuration
class FlywayInitializerJpaDependencyConfiguration : EntityManagerFactoryDependsOnPostProcessor("flywayInitializer")
PS:这是 Kotlin 代码,但您应该能够相当轻松地将其转换为 Java。
【讨论】:
嗨。是的,这正是我试图做的,请看我的评论;以编程方式进行配置。问题是,这是正确的方法吗?为什么以这种方式更改自动配置?如果我不能使用 application.properties,我如何为不同的环境配置不同的数据源?谢谢 你可以使用application.properties。只是不要期望 flyway 属性会产生任何影响,因为 Spring Boot 不会再读取和应用它们了。其他与 Flyway 无关的,仍然可以使用。 如何让它在 Spring Boot 测试中工作?我需要为 flyway 加载不同的属性以进行测试,但是 Flyway bean 不可用,或者当 Ier 手动创建 Flyway bean 时,其他 bean 会丢失。谢谢 @JBNizet 作为一个不了解 Kotlin 的人,除了最后一行,一切都可以理解。 @Younes_EO 最后一行:`@Configuration public static class FlywayInitializerJpaDependencyConfiguration extends EntityManagerFactoryDependsOnPostProcessor public FlywayInitializerJpaDependencyConfiguration() super("flywayInitializer"); `【参考方案2】:我为 Spring Boot 2.1.1 进行了配置,还必须重新定义 bean FlywayDefaultDdlModeProvider。
@Configuration
@ConditionalOnProperty(prefix = "spring.flyway", name = "enabled", matchIfMissing = true)
public class LegacyFlywayAutoConfiguration
@Bean
@Primary
public SchemaManagementProvider flywayDefaultDdlModeProvider(ObjectProvider<Flyway> flyways)
return new SchemaManagementProvider()
@Override
public SchemaManagement getSchemaManagement(DataSource dataSource)
return SchemaManagement.MANAGED;
;
@Bean(initMethod = "migrate")
public Flyway flyway(DataSource dataSource)
Flyway flyway = new Flyway();
flyway.setBaselineOnMigrate(true);
flyway.setDataSource(dataSource);
return flyway;
@Bean
public FlywayMigrationInitializer flywayInitializer(Flyway flyway)
return new FlywayMigrationInitializer(flyway, null);
/**
* Additional configuration to ensure that @link JdbcOperations beans depend
* on the @code flywayInitializer bean.
*/
@Configuration
@ConditionalOnClass(JdbcOperations.class)
@ConditionalOnBean(JdbcOperations.class)
protected static class FlywayInitializerJdbcOperationsDependencyConfiguration
extends JdbcOperationsDependsOnPostProcessor
public FlywayInitializerJdbcOperationsDependencyConfiguration()
super("flywayInitializer");
【讨论】:
你可以在@SpringBootTest 中使用它吗? 是的,被覆盖的配置本身适用于@SpringBootTest。但通常你不知道t want to use Oracle database for integration test, so I don
t 仅将其用于测试。我正在为@SpringBootTest 使用 H2 数据库,最新的 Flyway 版本没有任何问题。虽然,为了兼容性,我没有为集成测试创建自己的 Flyway 配置。
是的,这就是我想做的,但不知何故我想不出正确的方法。如果我在测试/资源中包含 application.yml,则 Flyway Bean 被实例化,并为版本 5+ 实例化。如果我将@Configuration 或@TestCONfiguration 放在某处,那么我可以通过编程方式创建它,但是其他Bean(Daos、Services)为空,因为我也需要手动创建它们。我只想手动创建 Flyway Bean,一切都留在 Spring 上。
必须将 spring.main.allow-bean-definition-overriding=true
添加到 application.properties 但它有效!【参考方案3】:
使用 Javassist 库,您可以检测 FlywayDB 库以记录不再支持 Oracle 版本,而不是引发致命异常(通过将 ensureDatabaseIsCompatibleWithFlywayEdition 方法调用包装在 try-catch 子句中)。就我而言,FlywayDB 社区版 (5.2.4) 似乎可以在我完成后与 Oracle 11.2 一起正常工作。这个解决方案有它的缺点,但在我的情况下它是最好的选择(数据库应该很快升级)所以也许有人会发现它也很有用。理想情况下,下面的代码应该先在您的应用程序中运行。 请自行承担使用风险。
public static void suppressIncompatibleDatabaseVersionCheck()
try
CtClass ctClass = ClassPool.getDefault().get("org.flywaydb.core.internal.database.base.Database");
ctClass.defrost();
CtMethod method = ctClass.getDeclaredMethod("ensureDatabaseIsCompatibleWithFlywayEdition");
CtClass etype = ClassPool.getDefault().get("java.lang.Exception");
method.addCatch(" LOG.warn(\"Exception suppressed: \" + $e); return ;", etype);
ctClass.toClass();
catch (NotFoundException | CannotCompileException e)
log.error("Could not instrument FlywayDB code.", e);
【讨论】:
【参考方案4】:使用下面的依赖,会被this解析。
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>5.2.3</version>
</dependency>
【讨论】:
正如我在问题中提到的,由于不支持 Oracle 11,我不能使用高于 4.2.0 的 flyway 版本 对我来说同样不能使用更高版本的flyway,除非你说flyway-core 5与ojdbc6 11和oracle 11兼容(不是)以上是关于Spring Boot 2.1.0 和 Flyway 4.2.0的主要内容,如果未能解决你的问题,请参考以下文章
spring-boot 2.1.0 mongo - CodecConfigurationException:找不到类 java.time.Year 的编解码器
rocketmq-spring-boot-starter 2.1.0 事务消息 txProducerGroup 移除解读