在liquibase的CustomTaskChange类中使用其他的spring beans

8 浏览
0 Comments

在liquibase的CustomTaskChange类中使用其他的spring beans

我需要进行一些数据迁移,但是在liquibase changeset中做这个操作太复杂了。我们使用spring。

所以我写了一个实现了liquibase.change.custom.CustomTaskChange类的类,并在changeset中引用它。

到这一步都还好。

我的问题是:

在这样的类中是否可以访问其他的spring beans?

当我尝试在这个类中使用一个autowired bean时,它是null的,这让我觉得可能在这个时候自动装配还没有完成?

我还在其他线程中读到,Liquibase bean必须在所有其他bean之前初始化,这是正确的吗?

这是我写的类的一部分代码:

@Component
public class UpdateJob2 implements CustomTaskChange {
private String param1;
@Autowired
private SomeBean someBean;
@Override
public void execute(Database database) throws CustomChangeException {
    try {
        List titleTypes = someBean.getSomeObjects(
                param1
        );
    } catch (Exception e) {         
        throw new CustomChangeException();
    }
...

我得到了一个异常,当我调试时,我可以看到someBean是null。

这是SpringLiquibase的配置:

@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
@ComponentScan({
"xxx.xxx.."})
public class DatabaseConfiguration {
@Bean
public SpringLiquibase springLiquibase() {
    SpringLiquibase liquibase = new SpringLiquibase();
    liquibase.setDataSource(dataSource());
    liquibase.setChangeLog("classpath:liquibase-changelog.xml");
    return liquibase;
}
...

还有一些其他的配置:



    

这是从changeset中的调用:




        
            
        

0
0 Comments

问题的原因是在Liquibase的CustomTaskChange类中无法使用其他的Spring beans。解决方法有两种:Solution A和Solution B。

Solution A是在官方的自定义变更示例中,通过使用反射来获取ApplicationContext并调用getBean方法来解决这个问题。

Solution B是通过创建一个自定义的Liquibase配置bean,并在其中创建一个扩展了SpringLiquibase的类BeanAwareSpringLiquibase来解决这个问题。BeanAwareSpringLiquibase类有一个对ApplicationContext的静态引用,可以在Spring Boot启动时自动注入ApplicationContext,从而在CustomTaskChange类中可以使用getBean方法来获取其他的Spring beans。

在CustomTaskChange对象中如何获取BeanAwareSpringLiquibase.getBean(...)呢?只需要直接调用BeanAwareSpringLiquibase.getBean方法即可。

需要注意的是,在使用自定义的Liquibase配置bean时,需要将其包路径添加到@SpringBootApplication注解的scanBasePackages属性中,以确保使用自定义的Liquibase配置而不是默认的LiquibaseAutoConfiguration。

另外,最好在execute方法之前的setUp方法中准备好所有需要使用的beans。

至于关于在创建新的模式(schema)时使用Liquibase的问题,目前还没有找到解决方法。

0
0 Comments

问题的出现原因是,某些bean(如JPA repositories)依赖于liquibase bean。在SpringLiquibase bean初始化时,liquibase运行changelogs,但整个Spring上下文在此时还没有完全加载。如果尝试自动装配依赖于liquibase的bean,在启动时会抛出异常。

为了解决这个问题,可以通过重写Spring Liquibase配置,并在自定义任务上设置一个静态字段来实现。在配置中设置字段可以确保在changeset运行之前设置该字段。

以下是解决方法的代码示例:

/**
    任务具有一个在LiquibaseConfiguration类中设置的静态成员。
*/
public class MyCustomTask implements CustomTaskChange {
    private static MyBean myBean;
    public static void setMyBean(MyBean myBean) {
        MyCustomTask.myBean = myBean;
    }
    public void execute(Database database) throws CustomChangeException {
        try {
            JdbcConnection jdbcConnection = (JdbcConnection) database.getConnection();
            // 使用myBean进行操作
        } catch (DatabaseException | SQLException e) {
            throw new CustomChangeException(e);
        }
    }
}
/**
    扩展SpringBoot Liquibase自动配置
    org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration.LiquibaseConfiguration
*/
(proxyBeanMethods = false)
@SpringLiquibase.class
({DataSourceProperties.class, LiquibaseProperties.class})
public static class MyLiquibaseConfiguration
        extends LiquibaseAutoConfiguration.LiquibaseConfiguration {
    /**
     * 自动装配myBean并将其设置在MyCustomTask上。
     *
     *  properties Liquibase的配置属性。
     *  myBean 自定义的bean。
     */
    public MigrationLiquibaseConfiguration(LiquibaseProperties properties, MyBean myBean) {
        super(properties);
        MyCustomTask.setMyBean(myBean);
    }
}

这种技术比静态地暴露整个应用程序上下文更安全。只有需要的字段会被传递给任务,并且之后这些字段不可公开访问。

0
0 Comments

问题的原因是changeset.xml中引用的类并不由Spring管理,因此无法使用依赖注入(DI)等功能。解决方法是将Spring beans注入到非Spring对象中。具体的解决方法是通过在由Spring管理的bean中公开ApplicationContext,然后CustomChange可以使用ApplicationContext来访问其他Spring beans。如果这个方法对你不起作用,请提供更多细节并创建一个新的问题。另外,也可以通过在启动后使用应用程序迁移来绕过这个问题。Liquibase的问题可能是在Spring bean初始化之前运行了liquibase。

0