【问题标题】:How to start H2 TCP server on Spring Boot application startup?如何在 Spring Boot 应用程序启动时启动 H2 TCP 服务器?
【发布时间】:2016-09-01 07:35:29
【问题描述】:

通过将以下行添加到 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);
    }
}

但是如果我在 Tomcat 上运行 WAR 文件,它就不起作用,因为没有调用 main 方法。有没有更好的通用方法如何在 bean 初始化之前在应用程序启动时启动 H2 TCP 服务器?我使用 Flyway(自动配置),它在“连接被拒绝:连接”上失败,可能是因为服务器没有运行。谢谢。

【问题讨论】:

标签: java spring tomcat spring-boot h2


【解决方案1】:

这个解决方案对我有用。如果应用程序作为 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】:

    是的,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.

    这回答了您的问题,但我认为如果它与您的 Spring Boot 应用程序一起部署,您可能应该使用嵌入式模式。这在资源上更快更轻。您只需指定正确的 URL,数据库就会启动:

    jdbc:h2:/usr/share/myDbFolder
    

    (straight out of the cheat sheet)。

    【讨论】:

    • 不幸的是,这对我不起作用。似乎自动配置的 Flyway bean 是在 H2 服务器 bean 之前创建的,并且在连接被拒绝时失败。我需要在任何 bean 之前启动 H2 服务器。
    • @Vojtech 如何让bean先依赖其他bean开始,见:stackoverflow.com/questions/7868335/…
    【解决方案3】:

    对于 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[] { "/" };
        }
    
    }
    

    【讨论】:

      【解决方案4】:

      其他答案中没有考虑到一个警告。您需要注意的是,启动服务器是对 DataSource bean 的临时依赖。这是因为DataSource只需要网络连接,不需要bean关系。

      这导致的问题是 spring-boot 在创建 DataSource 之前不知道需要启动 h2 数据库,因此您可能会在应用程序启动时出现连接异常。

      使用 spring-framework 这不是问题,因为您将数据库服务器启动放在根配置中,而数据库作为子项。使用 spring boot AFAIK 只有一个上下文。

      要解决这个问题,您可以在数据源上创建一个 Optional&lt;Server&gt; 依赖项。 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;
      }
      

      【讨论】:

        【解决方案5】:

        你可以这样做:

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

        【讨论】:

          猜你喜欢
          • 2018-01-19
          • 2020-08-14
          • 1970-01-01
          • 2020-11-05
          • 2015-08-18
          • 2015-07-22
          • 2022-07-08
          • 2017-02-28
          • 1970-01-01
          相关资源
          最近更新 更多