2016-05-06 59 views
5

sono in grado di avviare il server TCP H2 (database in un file) durante l'esecuzione di app come Primavera di avvio applicazione aggiungendo seguente riga nel metodo principale SpringBootServletInitializer:Come avviare il server H2 TCP all'avvio dell'applicazione Spring Boot?

@SpringBootApplication 
public class NatiaApplication extends SpringBootServletInitializer { 
    public static void main(String[] args) { 
     Server.createTcpServer().start(); 
     SpringApplication.run(NatiaApplication.class, args); 
    } 
} 

Ma se ho eseguito il file WAR su Tomcat non funziona perché il metodo principale non viene chiamato. C'è un modo universale migliore per avviare il server H2 TCP all'avvio dell'applicazione prima che i bean vengano inizializzati? Uso Flyway (autoconfig) e non riesce su "Connessione rifiutata: connetti" probabilmente perché il server non è in esecuzione. Grazie.

risposta

5

Questa soluzione funziona per me. Avvia il server H2 se l'app viene eseguita come app Spring Boot e anche se viene eseguita su Tomcat. La creazione del server H2 come bean non ha funzionato perché il bean Flyway è stato creato in precedenza e non è riuscito in "Connection refused".

@SpringBootApplication 
@Log 
public class NatiaApplication extends SpringBootServletInitializer { 

    public static void main(String[] args) { 
     startH2Server(); 
     SpringApplication.run(NatiaApplication.class, args); 
    } 

    @Override 
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 
     startH2Server(); 
     return application.sources(NatiaApplication.class); 
    } 

    private static void startH2Server() { 
     try { 
      Server h2Server = Server.createTcpServer().start(); 
      if (h2Server.isRunning(true)) { 
       log.info("H2 server was started and is running."); 
      } else { 
       throw new RuntimeException("Could not start H2 server."); 
      } 
     } catch (SQLException e) { 
      throw new RuntimeException("Failed to start H2 server: ", e); 
     } 
    } 
} 
2

Per il confezionamento guerra si può fare questo:

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { 

    @Override 
    protected Class<?>[] getRootConfigClasses() { 
     return null; 
    } 

    @Override 
    protected Class<?>[] getServletConfigClasses() { 
     Server.createTcpServer().start(); 
     return new Class[] { NatiaApplication.class }; 
    } 

    @Override 
    protected String[] getServletMappings() { 
     return new String[] { "/" }; 
    } 

} 
2

Yup, straight from the documentation, è possibile utilizzare un riferimento di fagioli:

<bean id = "org.h2.tools.Server" 
     class="org.h2.tools.Server" 
     factory-method="createTcpServer" 
     init-method="start" 
     destroy-method="stop"> 
<constructor-arg value="-tcp,-tcpAllowOthers,-tcpPort,8043" /> 

C'è anche un servlet listener option that auto-starts/stops it.

Quello risponde alla tua domanda, ma penso che probabilmente dovresti usare la e modalità mbedded invece se si sta distribuendo insieme alla tua applicazione Spring Boot. Questo è MOLTO più veloce e più leggero sulle risorse. È sufficiente specificare l'URL corretto e il database inizierà:

jdbc:h2:/usr/share/myDbFolder 

(straight out of the cheat sheet).

+0

Purtroppo questo non funziona per me. Sembra che il bean Flyway autoconfigurato venga creato prima del bean di server H2 e non riesca a rifiutare la connessione. Ho bisogno di avviare il server H2 prima di qualsiasi bean. – Vojtech

+0

@Vojtech Per sapere come fare in modo che i bean dipendano dagli altri bean che iniziano per primi, vedere: http: // stackoverflow.com/domande/7868335/primavera-make-sicuro-a-particolare-bean-viene-inizializzato-prima – BobMcGee

0

Si può fare in questo modo:

@Configuration 
public class H2ServerConfiguration { 

    @Value("${db.port}") 
    private String h2TcpPort; 

    /** 
    * TCP connection to connect with SQL clients to the embedded h2 database. 
    * 
    * @see Server 
    * @throws SQLException if something went wrong during startup the server. 
    * @return h2 db Server 
    */ 
    @Bean 
    public Server server() throws SQLException { 
     return Server.createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", h2TcpPort).start(); 
    } 

    /** 
    * @return FlywayMigrationStrategy the strategy for migration. 
    */ 
    @Bean 
    @DependsOn("server") 
    public FlywayMigrationStrategy flywayMigrationStrategy() { 
     return Flyway::migrate; 
    } 
} 
0

C'è un avvertimento che non è stata considerata nelle altre risposte. Quello di cui devi essere a conoscenza è che l'avvio di un server è una dipendenza temporanea dal tuo bean DataSource. Ciò è dovuto allo DataSource che richiede solo una connessione di rete, non una relazione bean.

Il problema che ne consegue è che la primavera-boot non sapere il database h2 bisogno di essere licenziato prima di creare il DataSource, così si potrebbe finire con l'eccezione di connessione all'avvio dell'applicazione.

Con spring-foundation questo non è un problema poiché si mette l'avvio del server DB nel RootConfig con il database come figlio. Con spring boot AFAIK c'è un solo contesto.

Per aggirare questo problema, è possibile creare una dipendenza Optional<Server> dall'origine dati. Il motivo per Optional è che potresti non avviare sempre il server (parametro di configurazione) per il quale potresti avere un DB di produzione.

@Bean(destroyMethod = "close") 
public DataSource dataSource(Optional<Server> h2Server) throws PropertyVetoException { 
    HikariDataSource ds = new HikariDataSource(); 
    ds.setDriverClassName(env.getProperty("db.driver")); 
    ds.setJdbcUrl(env.getProperty("db.url")); 
    ds.setUsername(env.getProperty("db.user")); 
    ds.setPassword(env.getProperty("db.pass")); 
    return ds; 
}