如何在 Spring 引导应用程序启动时启动 H2 TCP 服务器?
How to start H2 TCP server on Spring Boot application startup?
当 运行ning 应用程序作为 Spring 引导应用程序时,我可以通过将以下行添加到 SpringBootServletInitializer main 来启动 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(自动配置),它在 "Connection refused: connect" 上失败,可能是因为服务器不是 运行ning。谢谢。
对于 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[] { "/" };
}
}
是的,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 启动应用程序一起部署,您可能应该使用嵌入式模式。这是更快和更轻的资源。您只需指定正确的 URL,数据库就会启动:
jdbc:h2:/usr/share/myDbFolder
这个解决方案适合我。如果应用程序作为 Spring 启动应用程序运行并且在 Tomcat 上运行,它会启动 H2 服务器。将 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);
}
}
}
你可以这样做:
@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;
}
}
其他答案中没有考虑到一个警告。您需要注意的是,启动服务器是对 DataSource
bean 的暂时依赖。这是因为DataSource
只需要网络连接,不需要bean关系。
这导致的问题是 spring-boot 将不知道在创建 DataSource
之前需要启动的 h2 数据库,因此您最终可能会在应用程序上出现连接异常启动。
使用 spring-framework 这不是问题,因为您将数据库服务器启动放在根配置中,并将数据库作为子数据库。使用 spring 引导 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;
}
当 运行ning 应用程序作为 Spring 引导应用程序时,我可以通过将以下行添加到 SpringBootServletInitializer main 来启动 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(自动配置),它在 "Connection refused: connect" 上失败,可能是因为服务器不是 运行ning。谢谢。
对于 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[] { "/" };
}
}
是的,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 启动应用程序一起部署,您可能应该使用嵌入式模式。这是更快和更轻的资源。您只需指定正确的 URL,数据库就会启动:
jdbc:h2:/usr/share/myDbFolder
这个解决方案适合我。如果应用程序作为 Spring 启动应用程序运行并且在 Tomcat 上运行,它会启动 H2 服务器。将 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);
}
}
}
你可以这样做:
@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;
}
}
其他答案中没有考虑到一个警告。您需要注意的是,启动服务器是对 DataSource
bean 的暂时依赖。这是因为DataSource
只需要网络连接,不需要bean关系。
这导致的问题是 spring-boot 将不知道在创建 DataSource
之前需要启动的 h2 数据库,因此您最终可能会在应用程序上出现连接异常启动。
使用 spring-framework 这不是问题,因为您将数据库服务器启动放在根配置中,并将数据库作为子数据库。使用 spring 引导 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;
}