如果AppContext的初始化失败,则正确终止Spring Boot和Tomcat

时间:2018-03-06 16:01:31

标签: java spring tomcat spring-boot

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

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

  1. 这是预期的行为(Tomcat应该继续听吗?)
  2. 如何在应用程序上下文初始化失败时停止Spring Boot和Tomcat?
  3. 这里的日志示例:

    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)
    

    在此异常之后,Tomcat仍在指定端口上可用。

    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
    

    依赖关系:

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

1 个答案:

答案 0 :(得分:3)

中可能有两种情况
  

第一个场景

应用程序启动并运行,创建了应用程序上下文,然后在服务器中发生了一些运行时异常,并且您希望正常关闭。在这种情况下,您可以使用Spring boot Graceful shutdown

之类的实用程序

Ref: https://github.com/corentin59/spring-boot-graceful-shutdown

  

情景2:

这是Spring Boot无法创建Application上下文时发生的情况。您的方案属于此类别。当应用程序启动时,它会尝试连接application.properties中的配置,如果有任何问题,则不会创建应用程序上下文

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

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

在此之后,Tomcat实例将不会运行,并且可以使用端口