2016-05-06 126 views
5

我能夠通過添加下面一行到SpringBootServletInitializer主要方法運行的應用程序如春啓動應用程序時,啓動TCP H2服務器(在一個文件數據庫):如何在Spring Boot應用程序啓動時啓動H2 TCP服務器?

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

但如果我上運行WAR文件它不起作用,因爲主方法沒有被調用。在bean初始化之前,如何在應用程序啓動時啓動H2 TCP服務器,有更好的通用方法嗎?我使用Flyway(自動配置),並且由於服務器沒有運行而導致「Connection refused:connect」失敗。謝謝。

回答

5

此解決方案適用於我。如果應用程序以Spring Boot應用程序運行,並且運行在Tomcat上,它將啓動H2服務器。將H2服務器創建爲bean不起作用,因爲此前創建了Flyway bean,並在「連接被拒絕」時失敗。

@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

對於WAR包裝,你可以這樣做:

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

是啊,straight from the documentation,你可以使用一個bean引用:

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

還有一個servlet listener option that auto-starts/stops it.

那回答你的問題,但我認爲你應該使用e如果它是與Spring Boot應用程序一起部署的話,則可以使用mbedded模式。這在資源上更快更輕。您只需指定正確的URL並啓動數據庫:

jdbc:h2:/usr/share/myDbFolder 

straight out of the cheat sheet)。

+0

不幸的是,這並不適用於我。似乎自動配置的Flyway bean是在H2服務器bean之前創建的,並且連接拒絕失敗。我需要在任何bean之前啓動H2服務器。 – Vojtech

+0

@Vojtech有關如何使bean首先依賴於其他bean,請參閱:http:// stackoverflow。COM /問題/ 7868335 /彈簧化妝肯定-A-特定-豆被初始化爲先 – BobMcGee

0

你可以這樣做:

@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

有還沒有在其他的答案被認爲是一個警告。你需要注意的是,啓動一個服務器對你的DataSource bean是一個短暫的依賴。這是由於DataSource只需要一個網絡連接,而不是一個bean關係。

這會導致的問題是,在創建DataSource之前,spring-boot將不知道需要啓動的h2數據庫,因此最終可能會在應用程序啓動時出現連接異常。

使用spring-foundation時,這不是一個問題,因爲您將數據庫服務器的啓動放在RootConfig的數據庫作爲孩子。隨着春季開機AFAIK只有一個上下文。

爲了解決這個問題,你可以做的是創建一個Optional<Server>依賴於數據源。 Optional的原因是,您可能無法始終啓動可能有生產數據庫的服務器(配置參數)。

@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; 
} 
相關問題