2016-01-21 28 views
10

Próbuję wstrzyknąć składnik właściwości konfiguracyjnych w kodzie migracji Java, ale zawsze ma on wartość zerową.Fasolka wiosenna nie jest wstrzykiwana w locie opartym na migracji w oparciu o java

Używam sprężynowego buta z Flyway.

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

    private String codePath; 
} 

Następnie wewnątrz Flyway kodu migracji, próbując autowrire tego składnika w następujący sposób:

public class V1_4__Migrate_codes_metadata implements SpringJdbcMigration { 

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

Tutaj codesProp zawsze ma wartość null.

Czy istnieje sposób na wstrzyknięcie fasoli szparagowej wewnątrz drogi przelotowej lub zainicjowanie jej przed fasolą przelotu?

Dziękuję.

Odpowiedz

5

Flyway nie obsługuje wtrysku zależności w implementacjach SpringJdbcMigration. Po prostu wyszukuje klasy w ścieżce klas, która implementuje SpringJdbcMigration i tworzy nową instancję przy użyciu domyślnego konstruktora. Wykonuje się to w SpringJdbcMigrationResolver. Po przeprowadzeniu migracji SpringJdbcMigrationExecutor tworzy nowy JdbcTemplate, a następnie wywołuje metodę implementacji migracji migrate.

Jeśli naprawdę potrzebujesz wtyczek, które mają zostać wstrzyknięte w migracje oparte na Javie, myślę, że będziesz musiał zaimplementować swój własny MigrationResolver, który pobiera fasole określonego typu z kontekstu aplikacji i tworzy i zwraca instancję ResolvedMigration dla każdego .

+0

Dzięki, myślę, że jest to związane poprzez emisję https://github.com/flyway/flyway/issues/1062, teraz muszę zaimportować kilka kodów zapisanych w systemach plików do db. masz pomysł na odczytanie ścieżki zewnętrznej jako konfiguracji i przekazanie jej do przelotu. – Mango

3

Jeśli tak jak ja, nie chcesz czekać na Flyway 4.1, można użyć Flyway 4,0 i dodać następujące aplikacji Boot wiosny:

1) Utwórz klasę ApplicationContextAwareSpringJdbcMigrationResolver w projekcie:

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) Dodaj nową klasę konfiguracji odpowiedzieć proces Wiosna Boot generowane flyway instancję:

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()); 
       } 
      } 
     }; 
    } 
} 

Zauważ, że mam trochę sztywno zależeć encje na puli jdbc tomcat, h2 i mysql. Jeśli używasz czegoś innego, będziesz musiał zmienić kod tam (Jeśli jest ktoś, kto wie, jak tego uniknąć, prosimy o komentarz!)

Należy również pamiętać, że pakiet @ComponentScan musi pasować do miejsca, w Klasy migracji Java.

Należy również pamiętać, że musiałem dodać ponownie SqlMigrationResolver, ponieważ chcę wspierać zarówno SQL, jak i smak Java migracji.

3) Tworzenie klasy Javy w pakiecie db.migrations który ma rzeczywistej migracji:

@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(...); 
    } 
} 

Pamiętaj, że musisz dokonać klasy A @Component i musi wdrożyć SpringJdbcMigration. W tej klasie możesz użyć injekcyjnego konstruktora Spring dla dowolnego komponentu Spring bean z kontekstu, w którym będziesz musiał przeprowadzić migrację.

Uwaga: Pamiętaj, aby wyłączyć sprawdzanie ddl z hibernacji, ponieważ zatwierdzenie wydaje się uruchomić przed Flyway zjazdowe:

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

Wygląda tej funkcji jest dodawana do Flyway 5.0. To pytanie pojawiło się jako pierwszy wynik, gdy szukałem w Google informacji o "fasoli wiosennej", aby inne osoby nadal borykały się z tym problemem.

Jeśli utkniesz w Flyway 4.0, wymyśliłem inne szybkie rozwiązanie opublikowane na stronie spring-beans-flyway repository on my GitHub.

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

Możesz dodać adnotację @ComponentScan oprócz @SpringBootApplication.

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

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

Będziesz umieścić kod wewnątrz wdrożonego migrate(JdbcTemplate) metody, choć nie będzie faktycznie używać JdbcTemplate. Pozwoli to Flywayowi przeprowadzić migrację w porządku, podczas gdy twoja klasa pomocnika będzie wykonywała prace związane ze sprężyną.

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.

można wstrzyknąć fasoli musisz wewnątrz konstruktora. Migracja V ### może teraz korzystać z tych metod statycznych do pracy z ziarnami wiosennymi.

@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); 
    } 
} 
0

Jeśli korzystasz z deltaspike, możesz użyć BeanProvider, aby uzyskać odniesienie do swojej klasy. Oto przykład DAO, ale powinien on również dobrze pasować do twojej klasy.

Zmień swój kod DAO:

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

Następnie w metodzie migracji:

UserDao userdao = UserDao.getInstance(); 

I tam masz swoje odniesienie.

(odwołuje się od: Flyway Migration with java)