如果 AppContext 初始化失败,正确终止 Spring Boot 和 Tomcat [英] Properly terminate Spring Boot and Tomcat if initialization of AppContext fails

查看:35
本文介绍了如果 AppContext 初始化失败,正确终止 Spring Boot 和 Tomcat的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我在嵌入式 Tomcat 上启动 Spring Boot 应用程序并且在启动过程中出现故障(例如没有连接到 DB 或 Liquibase 更新失败或发现循环依赖等)时,Tomcat 继续侦听 8080 端口.

如果我向某个端点发送 HTTP 请求,应用程序将返回 404 NOT FOUND.

  1. 这是预期的行为吗(Tomcat 是否应该继续侦听)?
  2. 如何在应用上下文初始化失败时停止 Spring Boot 和 Tomcat?

这里的日志示例:

org.springframework.context.ApplicationContextException:无法启动嵌入式容器;嵌套异常是 org.springframework.beans.factory.BeanCreationException:在类路径资源 [org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfiguration$EmbeddedTomcat.class] 中定义的名称为tomcatEmbeddedServletContainerFactory"的 bean 创建时出错:bean 初始化失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:在类路径资源 [org/springframework/boot/autoconfigure/web/ServerPropertiesAutoConfiguration.class] 中定义名称为serverProperties"的 bean 创建时出错:bean 初始化失败;嵌套异常是 javax.validation.ValidationException:无法实例化配置.在 org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:137)在 org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:536)在 org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)在 org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)在 org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)在 org.springframework.boot.SpringApplication.run(SpringApplication.java:303)在 org.springframework.boot.SpringApplication.run(SpringApplication.java:1118)在 org.springframework.boot.SpringApplication.run(SpringApplication.java:1107)在 com.test.Application.main(Application.java:33)

此异常后,Tomcat 在指定端口上仍然可用.

UPD

application.properties:

spring.profiles.default=productionspring.application.name=测试spring.datasource.url=jdbc:postgresql://localhost:5432/testdbspring.datasource.username=testspring.datasource.password=test123spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialectspring.jpa.hibernate.ddl-auto=noneliquibase.change-log=classpath:/liquibase/changelog.xml

依赖:

<spring.boot.version>1.5.9.RELEASE</spring.boot.version><liquibase.version>3.5.3</liquibase.version><postgresql.version>9.4-1201-jdbc41</postgresql.version><hsqldb.version>2.4.0</hsqldb.version><powermock.version>1.7.3</powermock.version></属性><依赖项><依赖><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${spring.boot.version}</version><排除事项><排除><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-el</artifactId></排除><排除><groupId>org.apache.tomcat</groupId><artifactId>tomcat-annotations-api</artifactId></排除></排除项></依赖><依赖><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId><version>${spring.boot.version}</version><排除事项><排除><groupId>org.apache.tomcat</groupId><artifactId>tomcat-juli</artifactId></排除></排除项></依赖><依赖><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId><version>${spring.boot.version}</version><排除事项><排除><groupId>org.codehaus.groovy</groupId><artifactId>groovy</artifactId></排除><排除><groupId>nz.net.ultraq.thymeleaf</groupId><artifactId>thymeleaf-layout-dialect</artifactId></排除></排除项></依赖><依赖><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId><version>${spring.boot.version}</version><scope>编译</scope></依赖><依赖><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId><version>${spring.boot.version}</version></依赖><依赖><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>${spring.boot.version}</version></依赖><依赖><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><版本>4.3.14.RELEASE<范围>测试</范围></依赖><依赖><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId><version>${postgresql.version}</version></依赖><依赖><groupId>org.liquibase</groupId><artifactId>liquibase-core</artifactId><version>${liquibase.version}</version><scope>编译</scope></依赖><依赖><groupId>org.hsqldb</groupId><artifactId>hsqldb</artifactId><version>${hsqldb.version}</version><范围>测试</范围></依赖><依赖><groupId>org.powermock</groupId><artifactId>powermock-module-junit4</artifactId><version>${powermock.version}</version><范围>测试</范围></依赖><依赖><groupId>org.powermock</groupId><artifactId>powermock-api-mockito</artifactId><version>${powermock.version}</version><范围>测试</范围></依赖><依赖><groupId>org.hamcrest</groupId><artifactId>hamcrest-library</artifactId><version>${hamcrest.version}</version><范围>测试</范围></依赖><依赖><groupId>org.hamcrest</groupId><artifactId>hamcrest-core</artifactId><version>${hamcrest.version}</version><范围>测试</范围></依赖><依赖><groupId>com.google.code.simple-spring-memcached</groupId><artifactId>spring-cache</artifactId><version>3.6.1</version><排除事项><排除><groupId>org.hamcrest</groupId><artifactId>hamcrest-core</artifactId></排除><排除><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId></排除><排除><groupId>junit</groupId><artifactId>junit</artifactId></排除></排除项></依赖><依赖><groupId>org.codehaus.janino</groupId><artifactId>janino</artifactId><version>3.0.8</version></依赖><依赖><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></依赖><依赖><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId><version>1.2.3</version></依赖></依赖项><依赖管理><依赖项><依赖><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring.boot.version}</version><type>pom</type><范围>导入</范围></依赖></依赖项></dependencyManagement>

UPD 2

Application.java:

@SpringBootApplication@EnableJpaRepositories(basePackages = "com.test")@启用缓存@EnableScheduling公共类应用程序扩展 SpringBootServletInitializer {公共应用程序(){}public static void main(final String[] args) {SpringApplication.run(Application.class, args);}}

解决方案

这里可能有 2 个场景

<块引用>

第一场景

应用程序已启动并运行,应用程序上下文已创建,然后服务器中发生一些运行时异常,您想要正常关闭.在这种情况下,您可以使用像

<块引用>

场景 2:

这是当 Spring Boot 无法创建应用程序上下文本身时发生的场景.您的方案属于这一类.当应用程序启动时,它会尝试从 application.properties 连接配置,如果有任何问题,则不会创建应用程序上下文本身

因此在这种情况下,您不能选择正常关闭,因为您没有应用程序上下文的实例.在这种情况下,您可以捕获异常,选择适当的日志记录并手动退出系统

 尝试{SpringApplication.run(Application.class, args).close();;}捕获(异常前){System.out.println("准备退出");System.exit(-1);}

此后,Tomcat 实例将无法运行,端口将可用

When I start Spring Boot application on embedded Tomcat and something fails during startup (for instance there is no connection to DB or Liquibase update fails or circular dependency found, etc), Tomcat continues listening on 8080 port.

If I send HTTP request to some endpoint, an application returns 404 NOT FOUND.

  1. Is this expected behavior (should Tomcat continue listening)?
  2. How to stop Spring Boot and Tomcat when initialization of the application context fails?

Here EXAMPLE of the log:

org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tomcatEmbeddedServletContainerFactory' defined in class path resource [org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfiguration$EmbeddedTomcat.class]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serverProperties' defined in class path resource [org/springframework/boot/autoconfigure/web/ServerPropertiesAutoConfiguration.class]: Initialization of bean failed; nested exception is javax.validation.ValidationException: Unable to instantiate Configuration.
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:137)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:536)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107)
    at com.test.Application.main(Application.java:33)

After this exception Tomcat still available on the specified port.

UPD

application.properties:

spring.profiles.default=production
spring.application.name=test

spring.datasource.url=jdbc:postgresql://localhost:5432/testdb
spring.datasource.username=test
spring.datasource.password=test123
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

spring.jpa.hibernate.ddl-auto=none

liquibase.change-log=classpath:/liquibase/changelog.xml

dependencies:

<properties>
    <spring.boot.version>1.5.9.RELEASE</spring.boot.version>

    <liquibase.version>3.5.3</liquibase.version>
    <postgresql.version>9.4-1201-jdbc41</postgresql.version>
    <hsqldb.version>2.4.0</hsqldb.version>

    <powermock.version>1.7.3</powermock.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>${spring.boot.version}</version>
        <exclusions>
            <exclusion>
                <groupId>org.apache.tomcat.embed</groupId>
                <artifactId>tomcat-embed-el</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>tomcat-annotations-api</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
        <version>${spring.boot.version}</version>
        <exclusions>
            <exclusion>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>tomcat-juli</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
        <version>${spring.boot.version}</version>
        <exclusions>
            <exclusion>
                <groupId>org.codehaus.groovy</groupId>
                <artifactId>groovy</artifactId>
            </exclusion>
            <exclusion>
                <groupId>nz.net.ultraq.thymeleaf</groupId>
                <artifactId>thymeleaf-layout-dialect</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
        <version>${spring.boot.version}</version>
        <scope>compile</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
        <version>${spring.boot.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <version>${spring.boot.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>4.3.14.RELEASE</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>${postgresql.version}</version>
    </dependency>

    <dependency>
        <groupId>org.liquibase</groupId>
        <artifactId>liquibase-core</artifactId>
        <version>${liquibase.version}</version>
        <scope>compile</scope>
    </dependency>

    <dependency>
        <groupId>org.hsqldb</groupId>
        <artifactId>hsqldb</artifactId>
        <version>${hsqldb.version}</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4</artifactId>
        <version>${powermock.version}</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-api-mockito</artifactId>
        <version>${powermock.version}</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-library</artifactId>
        <version>${hamcrest.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-core</artifactId>
        <version>${hamcrest.version}</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>com.google.code.simple-spring-memcached</groupId>
        <artifactId>spring-cache</artifactId>
        <version>3.6.1</version>
        <exclusions>
            <exclusion>
                <groupId>org.hamcrest</groupId>
                <artifactId>hamcrest-core</artifactId>
            </exclusion>
            <exclusion>
                <groupId>commons-collections</groupId>
                <artifactId>commons-collections</artifactId>
            </exclusion>
            <exclusion>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.codehaus.janino</groupId>
        <artifactId>janino</artifactId>
        <version>3.0.8</version>
    </dependency>

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.2.3</version>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring.boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

UPD 2

Application.java:

@SpringBootApplication
@EnableJpaRepositories(basePackages = "com.test")
@EnableCaching
@EnableScheduling
public class Application extends SpringBootServletInitializer {

    public Application() {
    }

    public static void main(final String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

解决方案

There could be 2 scenarios in this

First Scenario

Application is up and running , the App Context is created and then some runtime exception occurs in the server and you want to do a graceful shutdown. In this scenario, you can use an utility like Spring boot Graceful shutdown

Scenario 2:

This is the scenario which occurs when Spring Boot is unable to create the Application context itself. Your scenario falls into this category. When application boots up, it tries to wire up the configurations from the application.properties and if there are any issues, the application context itself would not be created

Hence in this scenario , you cannot opt for a graceful shutdown as you don't have an instance of Application context. In such cases, you can catch the exception, choose appropriate logging and do a system exit manually

       try{
           SpringApplication.run(Application.class, args).close();;
        }
        catch(Exception ex){
            System.out.println("Going to exit");
            System.exit(-1);
        }

After this, Tomcat instance will not be running and Port would be available to use

这篇关于如果 AppContext 初始化失败,正确终止 Spring Boot 和 Tomcat的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆