一尘不染

具有JPA依赖关系的Flyway Spring Boot Autowired Bean

spring-boot

我正在使用Flyway 5.0.5,并且无法创建具有自动装配属性的java(SpringJdbcMigration)…它们最终会出现null

答案提到它已在Flyway 5中修复,但链接已失效。

我想念什么?


阅读 398

收藏
2020-05-30

共1个答案

一尘不染

由于依赖JPA,我为此苦了很长时间。我将略微修改我的问题的标题以反映这一点。

@AutowiredBean是从实例化的ApplicationContext。我们可以创建一个不同的bean,ApplicationContextAware然后使用它“手动连接”我们的bean以供迁移。

这里可以找到一种非常干净的方法。不幸的是,ApplicationContext使用JPA时会引发未捕获的异常(特别是null)。幸运的是,我们可以通过使用@DependsOn注释并ApplicationContext在设置之后强制飞行来解决此问题。

首先我们需要SpringUtilityavehlies/spring-beans- flyway2以上。

package com.mypackage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringUtility implements ApplicationContextAware {

    @Autowired
    private static ApplicationContext applicationContext;

    public void setApplicationContext(final ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    /*
        Get a class bean from the application context
     */
    public static <T> T getBean(final Class clazz) {
        return (T) applicationContext.getBean(clazz);
    }

    /*
        Return the application context if necessary for anything else
     */
    public static ApplicationContext getContext() {
        return applicationContext;
    }

}

随后,将配置flywayInitializer@DependsOnspringUtility。我扩展了FlywayAutoConfiguration此处,希望保留自动配置功能。除了在gradle.build文件中关闭flyway不再起作用之外,这似乎对我来说一直有效,因此我不得不添加,@Profile("!integration")以防止它在测试期间运行。除此之外,自动配置似乎对我有用,但是坦白地说,我只运行了一次迁移。希望如果我错了,有人会纠正我。

package com.mypackage;

import org.flywaydb.core.Flyway;
import org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializer;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration.FlywayConfiguration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.DependsOn;

import com.mypackage.SpringUtility;

@Configuration
@Profile("!integration")
class MyFlywayConfiguration extends FlywayConfiguration {
    @Primary
    @Bean(name = "flywayInitializer")
    @DependsOn("springUtility")
    public FlywayMigrationInitializer flywayInitializer(Flyway flyway){
        return super.flywayInitializer(flyway);
        //return new FlywayMigrationInitializer(flyway, null);
    }
}

为了完成示例,下面是一个迁移:

package db.migration;

import org.flywaydb.core.api.migration.spring.BaseSpringJdbcMigration;
import org.springframework.jdbc.core.JdbcTemplate;

import org.springframework.stereotype.Component;

import com.mypackage.repository.AccountRepository;
import com.mypackage.domain.Account;

import com.mypackage.SpringUtility;

import java.util.List;

public class V2__account_name_ucase_firstname extends BaseSpringJdbcMigration {

    private AccountRepository accountRepository = SpringUtility.getBean(AccountRepository.class);

    public void migrate(JdbcTemplate jdbcTemplate) throws Exception {

        List<Account> accounts = accountRepository.findAll();

        for (Account account : accounts) {

            String firstName = account.getFirstName();
            account.setFirstName(firstName.substring(0, 1).toUpperCase() + firstName.substring(1));
            account = accountRepository.save(account);

        }
    }
}

感谢github上的avehlies,堆栈溢出的Andy Wilkinson和github上的OldIMP一直为我提供帮助。

如果您使用的是Flyway的最新版本,请扩展BaseJavaMigration而不是BaseSpringJdbcMigration不推荐使用。另外,请查看用户Wim
Deblauwe 的以下两条
评论

2020-05-30