春豆没有注入基于迁移路线的Java迁移

问题描述:

我试图在迁移迁移java代码中注入配置属性的组件,但它始终为空。春豆没有注入基于迁移路线的Java迁移

我正在使用Flyway的弹簧引导。

@Component 
@ConfigurationProperties(prefix = "code") 
public class CodesProp { 

    private String codePath; 
} 

内。然后迁飞迁移代码,试图autowrire此组件如下:

public class V1_4__Migrate_codes_metadata implements SpringJdbcMigration { 

@Autowired 
private CodesProp codesProp ; 
public void migrate(JdbcTemplate jdbcTemplate) throws Exception { 
    codesProp.getCodePath(); 
} 

这里,codesProp始终为空。

有什么办法可以将spring bean注入到flyway中,或者在flyway bean之前初始化它吗?

谢谢。

Flyway不支持依赖注入SpringJdbcMigration实现。它只是在类路径中查找实现SpringJdbcMigration的类,并使用默认构造函数创建一个新实例。这在SpringJdbcMigrationResolver中执行。执行迁移时,SpringJdbcMigrationExecutor会创建一个新的JdbcTemplate,然后调用您的迁移实施的migrate方法。

如果你真的需要依赖关系注入到你的基于Java的迁移,我认为你必须实现自己的MigrationResolver从应用程序上下文检索特定类型的豆类和创建并返回一个ResolvedMigration实例为每。

+0

谢谢,我认为这是问题https://github.com/flyway/flyway/issues/1062相关的,现在,我需要导入存储在文件系统中的一些代码进入分贝。你有没有想过将外部路径作为配置读取并传递给flyway的问题。 – Mango

如果像我一样,你不希望等待迁飞4.1,你可以使用迁飞4.0及以下内容添加到您的春季启动应用程序:

1)在项目中创建一个ApplicationContextAwareSpringJdbcMigrationResolver类:

import org.flywaydb.core.api.FlywayException; 
import org.flywaydb.core.api.MigrationType; 
import org.flywaydb.core.api.MigrationVersion; 
import org.flywaydb.core.api.configuration.FlywayConfiguration; 
import org.flywaydb.core.api.migration.MigrationChecksumProvider; 
import org.flywaydb.core.api.migration.MigrationInfoProvider; 
import org.flywaydb.core.api.migration.spring.SpringJdbcMigration; 
import org.flywaydb.core.api.resolver.ResolvedMigration; 
import org.flywaydb.core.internal.resolver.MigrationInfoHelper; 
import org.flywaydb.core.internal.resolver.ResolvedMigrationComparator; 
import org.flywaydb.core.internal.resolver.ResolvedMigrationImpl; 
import org.flywaydb.core.internal.resolver.spring.SpringJdbcMigrationExecutor; 
import org.flywaydb.core.internal.resolver.spring.SpringJdbcMigrationResolver; 
import org.flywaydb.core.internal.util.ClassUtils; 
import org.flywaydb.core.internal.util.Location; 
import org.flywaydb.core.internal.util.Pair; 
import org.flywaydb.core.internal.util.StringUtils; 
import org.flywaydb.core.internal.util.scanner.Scanner; 
import org.springframework.context.ApplicationContext; 

import java.util.ArrayList; 
import java.util.Collection; 
import java.util.Collections; 
import java.util.Map; 

/** 
* Migration resolver for {@link SpringJdbcMigration}s which are registered in the given {@link ApplicationContext}. 
* This resolver provides the ability to use other beans registered in the {@link ApplicationContext} and reference 
* them via Spring's dependency injection facility inside the {@link SpringJdbcMigration}s. 
*/ 
public class ApplicationContextAwareSpringJdbcMigrationResolver extends SpringJdbcMigrationResolver { 

    private final ApplicationContext applicationContext; 

    public ApplicationContextAwareSpringJdbcMigrationResolver(Scanner scanner, Location location, FlywayConfiguration configuration, ApplicationContext applicationContext) { 
     super(scanner, location, configuration); 
     this.applicationContext = applicationContext; 
    } 

    @SuppressWarnings("unchecked") 
    @Override 
    public Collection<ResolvedMigration> resolveMigrations() { 
     // get all beans of type SpringJdbcMigration from the application context 
     Map<String, SpringJdbcMigration> springJdbcMigrationBeans = 
       (Map<String, SpringJdbcMigration>) this.applicationContext.getBeansOfType(SpringJdbcMigration.class); 

     ArrayList<ResolvedMigration> resolvedMigrations = new ArrayList<ResolvedMigration>(); 

     // resolve the migration and populate it with the migration info 
     for (SpringJdbcMigration springJdbcMigrationBean : springJdbcMigrationBeans.values()) { 
      ResolvedMigrationImpl resolvedMigration = extractMigrationInfo(springJdbcMigrationBean); 
      resolvedMigration.setPhysicalLocation(ClassUtils.getLocationOnDisk(springJdbcMigrationBean.getClass())); 
      resolvedMigration.setExecutor(new SpringJdbcMigrationExecutor(springJdbcMigrationBean)); 

      resolvedMigrations.add(resolvedMigration); 
     } 

     Collections.sort(resolvedMigrations, new ResolvedMigrationComparator()); 
     return resolvedMigrations; 
    } 

    ResolvedMigrationImpl extractMigrationInfo(SpringJdbcMigration springJdbcMigration) { 
     Integer checksum = null; 
     if (springJdbcMigration instanceof MigrationChecksumProvider) { 
      MigrationChecksumProvider version = (MigrationChecksumProvider) springJdbcMigration; 
      checksum = version.getChecksum(); 
     } 

     String description; 
     MigrationVersion version1; 
     if (springJdbcMigration instanceof MigrationInfoProvider) { 
      MigrationInfoProvider resolvedMigration = (MigrationInfoProvider) springJdbcMigration; 
      version1 = resolvedMigration.getVersion(); 
      description = resolvedMigration.getDescription(); 
      if (!StringUtils.hasText(description)) { 
       throw new FlywayException("Missing description for migration " + version1); 
      } 
     } else { 
      String resolvedMigration1 = ClassUtils.getShortName(springJdbcMigration.getClass()); 
      if (!resolvedMigration1.startsWith("V") && !resolvedMigration1.startsWith("R")) { 
       throw new FlywayException("Invalid Jdbc migration class name: " + springJdbcMigration.getClass() 
                            .getName() + " => ensure it starts with V or R," + " or implement org.flywaydb.core.api.migration.MigrationInfoProvider for non-default naming"); 
      } 

      String prefix = resolvedMigration1.substring(0, 1); 
      Pair info = MigrationInfoHelper.extractVersionAndDescription(resolvedMigration1, prefix, "__", ""); 
      version1 = (MigrationVersion) info.getLeft(); 
      description = (String) info.getRight(); 
     } 

     ResolvedMigrationImpl resolvedMigration2 = new ResolvedMigrationImpl(); 
     resolvedMigration2.setVersion(version1); 
     resolvedMigration2.setDescription(description); 
     resolvedMigration2.setScript(springJdbcMigration.getClass().getName()); 
     resolvedMigration2.setChecksum(checksum); 
     resolvedMigration2.setType(MigrationType.SPRING_JDBC); 
     return resolvedMigration2; 
    } 
} 

2)添加一个新的配置类发布过程中的春天引导产生的迁飞例如:

import org.flywaydb.core.Flyway; 
import org.flywaydb.core.internal.dbsupport.DbSupport; 
import org.flywaydb.core.internal.dbsupport.h2.H2DbSupport; 
import org.flywaydb.core.internal.dbsupport.mysql.MySQLDbSupport; 
import com.pegusapps.zebra.infrastructure.repository.flyway.ApplicationContextAwareSpringJdbcMigrationResolver; 
import org.flywaydb.core.internal.resolver.sql.SqlMigrationResolver; 
import org.flywaydb.core.internal.util.Location; 
import org.flywaydb.core.internal.util.PlaceholderReplacer; 
import org.flywaydb.core.internal.util.scanner.Scanner; 
import org.springframework.beans.BeansException; 
import org.springframework.beans.factory.config.BeanPostProcessor; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.ComponentScan; 
import org.springframework.context.annotation.Configuration; 

import javax.sql.DataSource; 
import java.sql.SQLException; 

@Configuration 
@ComponentScan("db.migration") 
public class FlywayConfiguration { 

    @Bean 
    public BeanPostProcessor postProcessFlyway(ApplicationContext context) { 
     return new BeanPostProcessor() { 

      @Override 
      public Object postProcessBeforeInitialization(Object o, String s) throws BeansException { 
       return o; 
      } 

      @Override 
      public Object postProcessAfterInitialization(Object o, String s) throws BeansException { 
       if (o instanceof Flyway) { 
        Flyway flyway = (Flyway) o; 
        flyway.setSkipDefaultResolvers(true); 
        ApplicationContextAwareSpringJdbcMigrationResolver resolver = new ApplicationContextAwareSpringJdbcMigrationResolver(
          new Scanner(Thread.currentThread().getContextClassLoader()), 
          new Location("classpath:db/migration"), 
          context.getBean(org.flywaydb.core.api.configuration.FlywayConfiguration.class), 
          context); 
        SqlMigrationResolver sqlMigrationResolver = null; 
        try { 
         sqlMigrationResolver = new SqlMigrationResolver(
           getDbSupport(), 
           new Scanner(Thread.currentThread().getContextClassLoader()), 
           new Location("classpath:db/migration"), 
           PlaceholderReplacer.NO_PLACEHOLDERS, 
           "UTF-8", 
           "V", 
           "R", 
           "__", 
           ".sql"); 
        } catch (SQLException e) { 
         e.printStackTrace(); 
        } 
        flyway.setResolvers(sqlMigrationResolver, resolver); 
       } 
       return o; 
      } 

      private DbSupport getDbSupport() throws SQLException { 
       DataSource dataSource = context.getBean(DataSource.class); 
       if(((org.apache.tomcat.jdbc.pool.DataSource)dataSource).getDriverClassName().equals("org.h2.Driver")) 
       { 
        return new H2DbSupport(dataSource.getConnection()); 
       } 
       else 
       { 
        return new MySQLDbSupport(dataSource.getConnection()); 
       } 
      } 
     }; 
    } 
} 

注意,我有些硬编码的依赖在tomcat jdbc池,h2和mysql上进行加密。如果你正在使用其他的东西,你需要在那里更改代码(如果有人知道如何避免它,请评论!)

另外请注意,@ComponentScan包需要匹配您将放置的位置Java迁移类。

另请注意,我必须重新添加SqlMigrationResolver,因为我想支持迁移的SQL和Java风格。

3)db.migrations包,做实际的迁移创建一个Java类:

@Component 
public class V2__add_default_surveys implements SpringJdbcMigration { 

    private final SurveyRepository surveyRepository; 

    @Autowired 
    public V2__add_surveys(SurveyRepository surveyRepository) { 
     this.surveyRepository = surveyRepository; 
    } 

    @Override 
    public void migrate(JdbcTemplate jdbcTemplate) throws Exception { 
     surveyRepository.save(...); 
    } 
} 

请注意,你需要做的类@Component,它需要实现SpringJdbcMigration。在这个类中,你可以从你的上下文中为任何Spring bean使用Spring构造器注入来完成迁移。

注:一定要禁用休眠的DDL验证,因为验证似乎迁飞运行之前运行:

spring.jpa.hibernate.ddl-auto=none 

它看起来像这样功能中Flyway 5.0添加。当我在Google上搜索“spring beans flyway”时,第一个结果就出现了这个问题,所以其他人可能仍然会遇到这个问题。

如果您遇到Flyway 4.0,我想出了另一个快速解决方案,发布在spring-beans-flyway repository on my GitHub页面。

1)Tell Spring to do a component scan of your db.migration directory

除了@SpringBootApplication之外,您还可以添加@ComponentScan注释。

@SpringBootApplication 
@ComponentScan({ "com.avehlies.springbeansflyway", "db.migration" }) 
public class SpringBeansFlywayApplication 

2)Create a SpringJdbcMigration in your db.migrations directory.

你把你的代码中实现migrate(JdbcTemplate)方法里面,虽然你不会实际使用的JdbcTemplate。这让Flyway能够按顺序运行迁移,同时让你的助手类完成与Spring相关的工作。

public class V2__Add_Person implements SpringJdbcMigration { 
    public void migrate(JdbcTemplate jdbcTemplate) { 
     Person person = new Person(4, 'Cosmo Kramer'); 
     AddPerson.addPerson(person); 
    } 
} 

3)Make a class annotated as a Component and create static methods in it.

你可以注入你需要的构造函数里面的豆子。 V ###迁移现在可以使用这些静态方法来使用Spring-wired bean进行操作。

@Component 
public class AddPerson { 
    private static PersonRepository personRepository; 

    public AddPerson(PersonRepository personRepository) { 
     this.personRepository = personRepository; 
    } 

    public static int addPerson(Person person) { 
     return personRepository.save(person); 
    } 
} 

如果您使用的是deltaspike,则可以使用BeanProvider获取对您的类的引用。这是一个DAO示例,但它也应该适合您的课程。

更改您的DAO代码:

public static UserDao getInstance() { 
    return BeanProvider.getContextualReference(UserDao.class, false, new DaoLiteral()); 
} 

然后在您的迁移方法:

UserDao userdao = UserDao.getInstance(); 

有你有你的参考。

(从引用:Flyway Migration with java