2016-05-06 5 views
5

Ich bin in der Lage, den H2 TCP Server (Datenbank in einer Datei) zu starten, wenn durch Zugabe folgende Zeile in die SpringBootServletInitializer Hauptmethode App als Frühling Boot-App ausgeführt wird:Wie startet man den H2 TCP Server beim Start der Spring Boot Anwendung?

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

Aber wenn ich die WAR-Datei laufe auf Tomcat funktioniert nicht, weil die Hauptmethode nicht aufgerufen wird. Gibt es eine bessere universelle Möglichkeit, den H2 TCP-Server beim Start der Anwendung zu starten, bevor die Beans initialisiert werden? Ich benutze Flyway (autoconfig) und es scheitert an "Connection refused: connect" wahrscheinlich weil der Server nicht läuft. Vielen Dank.

Antwort

5

Diese Lösung funktioniert für mich. Es startet den H2-Server, wenn die App als Spring Boot-App ausgeführt wird und wenn sie auf Tomcat ausgeführt wird. Das Erstellen des H2-Servers als Bean funktionierte nicht, da die Flyway-Bean früher erstellt wurde und bei "Verbindung abgelehnt" fehlgeschlagen ist.

@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

Für WAR Verpackung können Sie dies tun:

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, können Sie eine Bohne Referenz verwenden:

<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" /> 

Es gibt auch eine servlet listener option that auto-starts/stops it.

That Beantwortet Ihre Frage, aber ich denke, Sie sollten wahrscheinlich die e mbedded-Modus stattdessen, wenn es zusammen mit Ihrer Spring Boot-Anwendung bereitgestellt wird. Dies ist viel schneller und weniger Ressourcen. Sie geben einfach die richtige URL und die Datenbank starten:

jdbc:h2:/usr/share/myDbFolder 

(straight out of the cheat sheet).

+0

Leider funktioniert das nicht für mich. Es scheint, dass die automatisch konfigurierte Flyway-Bean vor dem H2-Server-Bean erstellt wurde und bei fehlgeschlagener Verbindung fehlschlägt. Ich brauche H2 Server vor irgendwelchen Beans gestartet zu werden. – Vojtech

+0

@Vojtech Wie Sie festlegen, dass Beans von anderen Beans abhängig sind, die zuerst gestartet werden, finden Sie unter: http: // stackoverflow.com/questions/7868335/spring-make-sure-a-particular-bohnen-initialisiert-zuerst – BobMcGee

0

Sie können wie folgt tun:

@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

Es gibt eine Einschränkung, die nicht in den anderen Antworten betrachtet hat. Sie müssen wissen, dass das Starten eines Servers eine vorübergehende Abhängigkeit von Ihrer DataSource-Bean ist. Dies ist aufgrund der DataSource nur eine Netzwerkverbindung, keine Bean-Beziehung.

Das Problem, das dies verursacht, ist, dass Spring-Boot nicht über die h2-Datenbank wissen muss vor dem Erstellen der gefeuert werden, so dass Sie mit einer Verbindungsausnahme beim Start der Anwendung enden können.

Mit Feder-Foundation ist dies kein Problem, wie Sie den DB-Server-Start in RootConfig mit der Datenbank als Kind setzen. Mit dem Springboot AFAIK gibt es nur einen einzigen Zusammenhang. Um dieses Problem zu umgehen, erstellen Sie eine Optional<Server> Abhängigkeit von der Datenquelle. Der Grund für Optional ist, dass Sie möglicherweise nicht immer den Server (Konfigurationsparameter) starten, für den Sie möglicherweise eine Produktionsdatenbank haben.

@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; 
} 
Verwandte Themen