복붙노트

[SPRING] 플라이 웨이 자바 기반 마이그레이션에 스프링 빈이 주입되지 않음

SPRING

플라이 웨이 자바 기반 마이그레이션에 스프링 빈이 주입되지 않음

이동 경로 마이그레이션 Java 코드에서 구성 등록 정보의 구성 요소를 주입하려고하지만 항상 null입니다.

플라이 웨이와 함께 봄 부츠를 사용하고 있습니다.

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

    private String codePath;
 }

그런 다음 이동 경로 마이그레이션 코드에서이 구성 요소를 다음과 같이 자동 실행하려고합니다.

public class V1_4__Migrate_codes_metadata implements SpringJdbcMigration {

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

여기에서 codesProp은 항상 null입니다.

플라이웨이 안에 스프링 콩을 주입하거나 플라이 웨이 콩 전에 초기화 할 수있는 방법이 있습니까?

고맙습니다.

해결법

  1. ==============================

    1.이동 경로는 SpringJdbcMigration 구현에 대한 종속성 주입을 지원하지 않습니다. SpringJdbcMigration을 구현하는 클래스 경로에서 클래스를 찾고 기본 생성자를 사용하여 새 인스턴스를 만듭니다. 이것은 SpringJdbcMigrationResolver에서 수행된다. 마이그레이션이 실행되면 SpringJdbcMigrationExecutor는 새 JdbcTemplate을 만든 다음 마이그레이션 구현의 마이그레이션 메서드를 호출합니다.

    이동 경로는 SpringJdbcMigration 구현에 대한 종속성 주입을 지원하지 않습니다. SpringJdbcMigration을 구현하는 클래스 경로에서 클래스를 찾고 기본 생성자를 사용하여 새 인스턴스를 만듭니다. 이것은 SpringJdbcMigrationResolver에서 수행된다. 마이그레이션이 실행되면 SpringJdbcMigrationExecutor는 새 JdbcTemplate을 만든 다음 마이그레이션 구현의 마이그레이션 메서드를 호출합니다.

    Java 기반 마이그레이션에 종속성을 실제로 주입해야하는 경우 응용 프로그램 컨텍스트에서 특정 유형의 Bean을 검색하고 각각에 대해 ResolvedMigration 인스턴스를 생성하고 반환하는 고유 한 MigrationResolver를 구현해야한다고 생각합니다.

  2. ==============================

    2.저와 같이 Flyway 4.1을 기다리지 않으려면 Flyway 4.0을 사용하고 Spring Boot 응용 프로그램에 다음을 추가하십시오 :

    저와 같이 Flyway 4.1을 기다리지 않으려면 Flyway 4.0을 사용하고 Spring Boot 응용 프로그램에 다음을 추가하십시오 :

    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 pool, h2 및 mysql에 대한 하드 코딩 된 종속성이 있음에 유의하십시오. 다른 것을 사용하는 경우 코드를 변경해야합니다 (피하는 방법을 알고있는 사람이 있으면 의견을 말하십시오).

    또한 @ComponentScan 패키지는 Java 이주 클래스를 넣을 위치와 일치해야합니다.

    또한 마이그레이션의 SQL과 Java 맛을 모두 지원하기 위해 SqlMigrationResolver를 다시 추가해야했습니다.

    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 빈에 Spring 생성자 삽입을 사용하여 마이그레이션을 수행해야 할 수도 있습니다.

    주의 : Flyway가 실행되기 전에 검증이 실행되는 것처럼 보이기 때문에 Hibernate의 ddl 유효성 검사를 비활성화하십시오 :

    spring.jpa.hibernate.ddl-auto=none
    
  3. ==============================

    3.deltaspike를 사용하는 경우 BeanProvider를 사용하여 클래스에 대한 참조를 얻을 수 있습니다. 다음은 DAO 예제이지만 클래스와도 잘 동작합니다.

    deltaspike를 사용하는 경우 BeanProvider를 사용하여 클래스에 대한 참조를 얻을 수 있습니다. 다음은 DAO 예제이지만 클래스와도 잘 동작합니다.

    DAO 코드 변경 :

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

    그런 다음 이주 f}에서 다음을 수행하십시오.

    UserDao userdao = UserDao.getInstance();
    

    그리고 거기에 참고 자료가 있습니다.

    (참조 : 마이 그 레이션 마이 그 레이션)

  4. from https://stackoverflow.com/questions/34923868/spring-beans-are-not-injected-in-flyway-java-based-migration by cc-by-sa and MIT license