优雅的关闭springboot程序

使用jar形式部署springboot程序后,通过kill进程关闭程序,总是不踏实。好在,官方提供了优雅关闭应用程序的方式。

引入依赖

首先,在POM中引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

配置application

以2.1.8.RELEASE为例,application.yml配置如下:

management:
  endpoint:
    shutdown:
      enabled: true
  endpoints:
    web:
      exposure:
        include: "*"
      base-path: /actuator

发送POST请求

curl -d "" --header "Content-Type:application/json" http://127.0.0.1:8080/actuator/shutdown
{"message":"Shutting down, bye..."}

Spring Boot Actuator

actuator可以帮助你监控和管理Spring Boot应用,比如健康检查、审计、统计和HTTP追踪等。所有的这些特性可以通过JMX或者HTTP endpoints来获得。
Actuator通过创建Endpoint来暴露HTTP或者JMX来监控和管理应用。

Endpoint

Endpoint 说明
auditevents 显示应用暴露的审计事件 (比如认证进入、订单失败)
info 显示应用的基本信息
health 显示应用的健康状态
metrics 显示应用多样的度量信息
loggers 显示和修改配置的loggers
logfile 返回log file中的内容(如果logging.file或者logging.path被设置)
httptrace 显示HTTP足迹,最近100个HTTP request/repsponse
env 显示当前的环境特性
flyway 显示数据库迁移路径的详细信息
liquidbase 显示Liquibase 数据库迁移的纤细信息
shutdown 让你逐步关闭应用
mappings 显示所有的@RequestMapping路径
scheduledtasks 显示应用中的调度任务
threaddump 执行一个线程dump
heapdump 返回一个GZip压缩的JVM堆dump

默认,除了shutdown所有的endpints都是打开的。

打开关闭Endpoint

你可以通过设置management.endpoint.<id>.enabled to true or false来决定打开还是关闭一个actuator endpoint。启用shutdown如下:

management.endpoint.shutdown.enabled=true

暴露Endpoint

通过HTTP暴露Actuator endpoints
management.endpoints.web.exposure.include=* 
management.endpoints.web.exposure.exclude=health,info

通过JMX暴露Actuator endpoints

management.endpoints.jmx.exposure.include=*
management.endpoints.jmx.exposure.exclude=

打开全部Endpoint后,访问http://127.0.0.1:8080/actuator如下:

{
  _links: {
    self: {
      href: "http://127.0.0.1:8080/actuator",
      templated: false
    },
    auditevents: {
      href: "http://127.0.0.1:8080/actuator/auditevents",
      templated: false
    },
    beans: {
      href: "http://127.0.0.1:8080/actuator/beans",
      templated: false
    },
    caches-cache: {
      href: "http://127.0.0.1:8080/actuator/caches/{cache}",
      templated: true
    },
    caches: {
      href: "http://127.0.0.1:8080/actuator/caches",
      templated: false
    },
    health: {
      href: "http://127.0.0.1:8080/actuator/health",
      templated: false
    },
    health-component: {
      href: "http://127.0.0.1:8080/actuator/health/{component}",
      templated: true
    },
    health-component-instance: {
      href: "http://127.0.0.1:8080/actuator/health/{component}/{instance}",
      templated: true
    },
    conditions: {
      href: "http://127.0.0.1:8080/actuator/conditions",
      templated: false
    },
    shutdown: {
      href: "http://127.0.0.1:8080/actuator/shutdown",
      templated: false
    },
    configprops: {
      href: "http://127.0.0.1:8080/actuator/configprops",
      templated: false
    },
    env: {
      href: "http://127.0.0.1:8080/actuator/env",
      templated: false
    },
    env-toMatch: {
      href: "http://127.0.0.1:8080/actuator/env/{toMatch}",
      templated: true
    },
    info: {
      href: "http://127.0.0.1:8080/actuator/info",
      templated: false
    },
    loggers: {
      href: "http://127.0.0.1:8080/actuator/loggers",
      templated: false
    },
    loggers-name: {
      href: "http://127.0.0.1:8080/actuator/loggers/{name}",
      templated: true
    },
    heapdump: {
      href: "http://127.0.0.1:8080/actuator/heapdump",
      templated: false
    },
    threaddump: {
      href: "http://127.0.0.1:8080/actuator/threaddump",
      templated: false
    },
    metrics: {
      href: "http://127.0.0.1:8080/actuator/metrics",
      templated: false
    },
    metrics-requiredMetricName: {
      href: "http://127.0.0.1:8080/actuator/metrics/{requiredMetricName}",
      templated: true
    },
    scheduledtasks: {
      href: "http://127.0.0.1:8080/actuator/scheduledtasks",
      templated: false
    },
    httptrace: {
      href: "http://127.0.0.1:8080/actuator/httptrace",
      templated: false
    },
    mappings: {
      href: "http://127.0.0.1:8080/actuator/mappings",
      templated: false
    }
  }
}

安全

考虑到可能造成信息泄露等严重的安全隐患,可以使用security机制。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

引入这个依赖之后,所有的接口都访问不了了,需要填写用户名和密码。

spring:
  security:
    user:
      name: admin
      password: admin
      roles: ADMIN

management:
  server:
    port: 8081      

通过下面自定义Security配置类,可以对/actuator开始的url访问要求有ADMIN权限,其他的随意访问。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
				.antMatchers("/actuator/**").access("hasRole('ADMIN')")
				.antMatchers("/**").permitAll();
		super.configure(http);
	}
}