今天早上启动项目,突然出现了如下异常,百度了一下没有合适的解决方案,决定从源码入手,看看能不能解决。
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.api.exception.FlywayValidateException: Validate failed: Migrations have failed validation
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1786) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:917) ~[spring-context-5.3.4.jar:5.3.4]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:582) ~[spring-context-5.3.4.jar:5.3.4]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) ~[spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:767) ~[spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) ~[spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426) ~[spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:326) ~[spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1311) ~[spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) ~[spring-boot-2.4.3.jar:2.4.3]
at com.zhx.realpro.CloudAlarmApplication.main(CloudAlarmApplication.java:33) ~[classes/:na]
Caused by: org.flywaydb.core.api.exception.FlywayValidateException: Validate failed: Migrations have failed validation
at org.flywaydb.core.Flyway$1.execute(Flyway.java:172) ~[flyway-core-7.1.1.jar:na]
at org.flywaydb.core.Flyway$1.execute(Flyway.java:164) ~[flyway-core-7.1.1.jar:na]
at org.flywaydb.core.Flyway.execute(Flyway.java:538) ~[flyway-core-7.1.1.jar:na]
at org.flywaydb.core.Flyway.migrate(Flyway.java:164) ~[flyway-core-7.1.1.jar:na]
at org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializer.afterPropertiesSet(FlywayMigrationInitializer.java:66) ~[spring-boot-autoconfigure-2.4.3.jar:2.4.3]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1845) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782) ~[spring-beans-5.3.4.jar:5.3.4]
... 19 common frames omitted
根据错误信息,报的是FlywayValidateException异常,找到这个类打上断点
启动项目,查看调用链
找到了抛出异常的位置,在它前面的这行打上断点启动项目,因为是这个结果判断之后才抛出异常
ValidateResult validateResult = doValidate(database, migrationResolver, schemaHistory, schemas, callbackExecutor, true);
跟进这行去看
ValidateResult validateResult = new DbValidate(database, schemaHistory, schemas, migrationResolver, configuration, ignorePending, callbackExecutor).validate();
validate方法里面,在Callable的call方法做校验,这块感觉有点过度设计了,没找到另起线程的好处。
migrationInfoService的refresh方法sql文件加载进来了,这块就不看了。接着往下进入List
验证所有sql文件的checksum,如果sql文件是第一次执行,会产生一个checksum。之后改了sql文件的内容checksum的值就会发生改变,从而验证失败validateError就不会为空,那么invalidMigrations就会添加一条。进入migrationInfo.validate();
走到这块发现两个checksum不一致。跟进去resolvedMigration.checksumMatches
不一致就返回false
返回一个ErrorDetails,错误信息很详细,不过最终却没有输出,看看怎么回事,返回到DbValidate.DbValidate方法,call执行之后返回了result。
目前为止result里面还是有详细的错误信息的
校验失败的sql文件不为空就进入 validationError = new ErrorDetails(ErrorCode.VALIDATE_ERROR, "Migrations have failed validation");
,这里的异常信息写死成“Migrations have failed validation”,导致更加详细的错误信息没有输出,记得老版本的flyway是有输出的。这样改了反而不直观。返回到Flyway.migrate
校验失败,抛出异常信息“ Migrations have failed validation”。
前面已经讲到一般是由于sql文件在第一次执行之后发生了改变导致的。