简体   繁体   English

如何在Spring Boot应用程序启动时启动H2 TCP服务器?

[英]How to start H2 TCP server on Spring Boot application startup?

I'm able to start the H2 TCP server (database in a file) when running app as Spring Boot app by adding following line into the SpringBootServletInitializer main method: 通过在SpringBootServletInitializer主方法中添加以下行,当我将应用程序作为Spring Boot应用程序运行时,我可以启动H2 TCP服务器(文件中的数据库):

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

But if I run the WAR file on Tomcat it doesn't work because the main method is not called. 但是如果我在Tomcat上运行WAR文件它不起作用,因为没有调用main方法。 Is there a better universal way how to start the H2 TCP server on the application startup before beans get initialized? 在bean初始化之前,如何在应用程序启动时启动H2 TCP服务器有更好的通用方法吗? I use Flyway (autoconfig) and it fails on "Connection refused: connect" probably because the server is not running. 我使用Flyway(autoconfig),它在“Connection refused:connect”上失败,可能是因为服务器没有运行。 Thank you. 谢谢。

This solution works for me. 这个解决方案适合我。 It starts the H2 server if the app runs as Spring Boot app and also if it runs on Tomcat. 如果应用程序作为Spring Boot应用程序运行,并且如果它在Tomcat上运行,它将启动H2服务器。 Creating H2 server as a bean did not work because the Flyway bean was created earlier and failed on "Connection refused". 将H2服务器创建为bean不起作用,因为先前创建了Flyway bean并且“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);
        }
    }
}

Yup, straight from the documentation , you can use a bean reference: 是的, 直接从文档中 ,您可以使用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" />

There's also a servlet listener option that auto-starts/stops it. 还有一个servlet侦听器选项可以自动启动/停止它。

That answers your question, but I think you should probably be using the embedded mode instead if it's deploying along with your Spring Boot application. 这回答了你的问题,但我认为如果它与你的Spring Boot应用程序一起部署,你应该使用嵌入式模式。 This is MUCH faster and lighter on resources. 这在资源上更快,更轻。 You simply specify the correct URL and the database will start: 您只需指定正确的URL,数据库就会启动:

jdbc:h2:/usr/share/myDbFolder

( straight out of the cheat sheet ). 直接从备忘单中 )。

For WAR packaging you can do this: 对于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[] { "/" };
    }

}

You can do like this: 你可以这样做:

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

There's a caveat that hasn't been considered in the other answers. 在其他答案中没有考虑过一个警告。 What you need to be aware of is that starting a server is a transient dependency on your DataSource bean. 您需要注意的是,启动服务器是对DataSource bean的暂时依赖。 This is due to the DataSource only needing a network connection, not a bean relationship. 这是因为DataSource只需要网络连接,而不是bean关系。

The problem this causes is that spring-boot will not know about the h2 database needing to be fired up before creating the DataSource , so you could end up with a connection exception on application startup. 这导致的问题是spring-boot不会知道在创建DataSource之前需要启动的h2数据库,因此最终可能会在应用程序启动时出现连接异常。

With the spring-framework this isn't a problem as you put the DB server startup in the root config with the database as a child. 使用spring-framework,这不是问题,因为您将数据库服务器启动放在root配置中,并将数据库作为子项。 With spring boot AFAIK there's only a single context. 使用弹簧靴AFAIK,只有一个上下文。

To get around this what you can do is create an Optional<Server> dependency on the data-source. 要解决此问题,您可以在数据源上创建一个Optional<Server>依赖项。 The reason for Optional is you may not always start the server (configuration parameter) for which you may have a production DB. 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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM