一起来学SpringCloud之 - 优雅关闭服务下线(Jetty)

本文介绍了如何使用SpringCloud的Actuator模块进行优雅的服务关闭,避免中断请求并确保服务在下线前完成当前处理。通过启动battcn-cloud-discovery和battcn-cloud-hello示例服务,演示了发送HTTP请求触发shutdown操作的过程,并分析了日志以展示服务的平滑关闭流程。完整代码和作者联系方式见文末。

在很多时候 kill -9 pid并不是很友好的方法,那样会将我们正在执行请求给断掉,同时eureka 中服务依旧是处于在线状态,这个时候我们可以使用官方提供的actuator来做优雅的关闭处理

- Actuator

spring-boot-actuator模块提供了一个监控和管理生产环境的模块,可以使用http、jmx、ssh、telnet等拉管理和监控应用。审计(Auditing)、健康(health)、数据采集(metrics gathering)会自动加入到应用里面。

- 开始

如果对Eureka不熟悉的可以参考:一起来学SpringCloud之-注册中心(Eureka/Consul)

- battcn-cloud-discovery

pom.xml导入eureka-server

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka-server</artifactId>
    </dependency>
</dependencies>

application.yml 配置内容

server:
  port: 7001
spring:
  application:
    name: battcn-cloud-discovery
eureka:
  instance:
    hostname: localhost
    prefer-ip-address: true
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

DiscoveryApplication 主函数启动类

@SpringBootApplication
@EnableEurekaServer
public class DiscoveryApplication {
    public static void main(String[] args) {
        SpringApplication.run(DiscoveryApplication.class, args);
    }
}

- battcn-cloud-hello

pom.xml导入eurekaactuator,注意该处不能用tomcat(原因还没找到,用tomcat报错,有兴趣的可以自己也试试)

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jetty</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>

application.yml 配置内容

server.port: 7002
spring.application.name: battcn-cloud-hello
endpoints.shutdown.enabled: true    #开启优雅关闭方式
management.security.enabled: false  #关闭安全认证
eureka:
  instance:
    hostname: localhost
    prefer-ip-address: true
  client:
    service-url:
      defaultZone: http://${eureka.instance.hostname}:7001/eureka/

HelloApplication 主函数与测试方法

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class HelloApplication {
    static Logger LOGGER = LoggerFactory.getLogger(HelloApplication.class);
    @GetMapping("/h1")
    public void home() {
        for (int i = 1;i < 6;i++) {
            try {
                Thread.sleep(i * 500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            LOGGER.info("[当前进度] - [{}]",i);
        }
    }

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

- 测试

1.分别启动battcn-cloud-discoverybattcn-cloud-hello两个服务

2.GET请求访问 http://192.168.206.1:7002/h1

3.POST请求访问:http://192.168.206.1:7002/shutdown

PostMan

- 日志分析

  • battcn-cloud-discovery
2017-08-20 11:50:38.257  INFO 6776 --- [nio-7001-exec-3] c.n.e.registry.AbstractInstanceRegistry  : Registered instance BATTCN-CLOUD-HELLO/192.168.206.1:battcn-cloud-hello:7002 with status DOWN (replication=false)
2017-08-20 11:50:38.259  INFO 6776 --- [nio-7001-exec-8] c.n.e.registry.AbstractInstanceRegistry  : Cancelled instance BATTCN-CLOUD-HELLO/192.168.206.1:battcn-cloud-hello:7002 (replication=false)
2017-08-20 11:50:38.765  INFO 6776 --- [nio-7001-exec-5] c.n.e.registry.AbstractInstanceRegistry  : Registered instance BATTCN-CLOUD-HELLO/192.168.206.1:battcn-cloud-hello:7002 with status DOWN (replication=true)
2017-08-20 11:50:38.766  INFO 6776 --- [nio-7001-exec-5] c.n.e.registry.AbstractInstanceRegistry  : Cancelled instance BATTCN-CLOUD-HELLO/192.168.206.1:battcn-cloud-hello:7002 (replication=true)
  • battcn-cloud-hello
2017-08-20 11:50:34.911  INFO 1304 --- [qtp161672347-19] com.battcn.HelloApplication              : [当前进度] - [1]
2017-08-20 11:50:35.912  INFO 1304 --- [qtp161672347-19] com.battcn.HelloApplication              : [当前进度] - [2]
2017-08-20 11:50:37.413  INFO 1304 --- [qtp161672347-19] com.battcn.HelloApplication              : [当前进度] - [3]
2017-08-20 11:50:38.251  INFO 1304 --- [      Thread-28] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@1c481ff2: startup date [Sun Aug 20 11:50:24 CST 2017]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@60dcc9fe
2017-08-20 11:50:38.252  INFO 1304 --- [      Thread-28] o.s.c.n.e.s.EurekaServiceRegistry        : Unregistering application battcn-cloud-hello with eureka with status DOWN
2017-08-20 11:50:38.252  WARN 1304 --- [      Thread-28] com.netflix.discovery.DiscoveryClient    : Saw local status change event StatusChangeEvent [timestamp=1503201038252, current=DOWN, previous=UP]
2017-08-20 11:50:38.252  INFO 1304 --- [      Thread-28] com.netflix.discovery.DiscoveryClient    : Shutting down DiscoveryClient ...
2017-08-20 11:50:38.252  INFO 1304 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_BATTCN-CLOUD-HELLO/192.168.206.1:battcn-cloud-hello:7002: registering service...
2017-08-20 11:50:38.253  INFO 1304 --- [      Thread-28] com.netflix.discovery.DiscoveryClient    : Unregistering ...
2017-08-20 11:50:38.258  INFO 1304 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_BATTCN-CLOUD-HELLO/192.168.206.1:battcn-cloud-hello:7002 - registration status: 204
2017-08-20 11:50:38.260  INFO 1304 --- [      Thread-28] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_BATTCN-CLOUD-HELLO/192.168.206.1:battcn-cloud-hello:7002 - deregister  status: 200
2017-08-20 11:50:38.264  INFO 1304 --- [      Thread-28] com.netflix.discovery.DiscoveryClient    : Completed shut down of DiscoveryClient
2017-08-20 11:50:38.265  INFO 1304 --- [      Thread-28] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 0
2017-08-20 11:50:38.269  INFO 1304 --- [      Thread-28] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown
2017-08-20 11:50:38.270  INFO 1304 --- [      Thread-28] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans
2017-08-20 11:50:38.283  INFO 1304 --- [      Thread-28] o.e.jetty.server.AbstractConnector       : Stopped ServerConnector@622fdb81{HTTP/1.1,[http/1.1]}{0.0.0.0:7002}
2017-08-20 11:50:38.283  INFO 1304 --- [      Thread-28] org.eclipse.jetty.server.session         : Stopped scavenging
2017-08-20 11:50:38.290  INFO 1304 --- [      Thread-28] o.e.j.s.h.ContextHandler.application     : Destroying Spring FrameworkServlet 'dispatcherServlet'
2017-08-20 11:50:38.291  INFO 1304 --- [      Thread-28] o.e.jetty.server.handler.ContextHandler  : Stopped o.s.b.c.e.j.JettyEmbeddedWebAppContext@987455b{/,[file:///C:/Users/Levin/AppData/Local/Temp/jetty-docbase.3368921683179226836.7002/],UNAVAILABLE}
2017-08-20 11:50:39.414  INFO 1304 --- [qtp161672347-19] com.battcn.HelloApplication              : [当前进度] - [4]
2017-08-20 11:50:41.915  INFO 1304 --- [qtp161672347-19] com.battcn.HelloApplication              : [当前进度] - [5]

从上述两端日志中可以看出,当我们发送shutdown命令的时候,会先通知eureka做服务下线处理,防止后续请求继续获取服务列表,然后当前服务的请求会继续执行,直到处理完毕后关闭进程,有兴趣的可以自己看看org.springframework.boot.actuate.endpoint.ShutdownEndpoint

- 说点什么

本章代码(battcn-cloud-discovery/battcn-cloud-hello):https://git.oschina.net/battcn/battcn-cloud/tree/master/battcn-cloud-shutdown

如有问题请及时与我联系

  • 个人QQ:1837307557
  • battcn开源群(适合新手):391619659
  • Spring Cloud中国社区①:415028731
  • Spring For All 社区⑤:157525002
<think>我们正在解决Maven依赖解析问题,特别是关于`spring-boot-starter-jetty`依赖无法解析的情况。根据用户提供的引用[^1]是关于如何注册错误页面的,引用[^2]则是Gradle构建脚本的插件配置,这两个引用与当前问题关系不大,因此我们主要依赖已知的Maven知识来解决。用户的问题:无法解析`org.springframework.boot:spring-boot-starter-jetty`依赖。常见原因和解决步骤:1.**检查Maven仓库配置**:确保你的Maven设置(settings.xml)中配置了正确的远程仓库,特别是Spring的仓库(如SpringBoot的仓库)或Maven中央仓库。2.**检查依赖坐标**:确认依赖的写法正确,包括groupId、artifactId和version。通常,SpringBoot的starter依赖需要指定版本,或者通过父项目继承版本。3.**检查SpringBoot父项目**:推荐使用SpringBoot的父项目来管理依赖版本。在pom.xml中:```xml<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.0</version><!--使用最新的稳定版本--></parent>```4.**显式指定版本**:如果没有使用父项目,需要在依赖中显式指定版本:```xml<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jetty</artifactId><version>2.7.0</version><!--替换为实际需要的版本--></dependency>```5.**检查依赖范围**:确保依赖没有被错误地放在`<dependencyManagement>`中,而没有在实际的依赖部分声明。6.**清理Maven本地仓库**:有时候本地仓库的依赖损坏,可以尝试删除本地仓库中对应依赖的目录,然后重新下载。7.**检查网络和代理设置**:确保Maven能够访问远程仓库。8.**确认Jetty依赖的可用性**:在Maven中央仓库中检查该依赖是否存在。可以通过访问:https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jetty9.**使用正确的SpringBoot版本**:注意SpringBoot的版本与Jettystarter的版本要匹配。10.**如果使用SpringBoot的WebStarter,需要排除Tomcat**:因为SpringBoot默认使用Tomcat,所以如果要使用Jetty,需要排除Tomcat依赖并添加Jetty:```xml<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jetty</artifactId></dependency>```根据上述步骤,逐步排查,通常问题可以解决。如果问题仍然存在,请提供你的pom.xml文件片段,以便进一步分析。生成相关问题:1.如何在Maven中配置Spring仓库?2.如何排除SpringBoot默认的Tomcat依赖?3.SpringBoot中如何使用Jetty替代Tomcat?</think> ### 解决无法解析Spring Boot Jetty依赖问题 此问题通常由以下原因引起,请逐步排查: #### ✅ 1. 检查Maven中央仓库可用性 确保你的网络可以访问Maven中央仓库,访问以下链接测试: ``` https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-starter-jetty/ ``` 如不可达,需检查网络或代理设置。 #### ✅ 2. 添加版本号 (最常见原因) 在`pom.xml`中**必须**明确指定Jetty依赖版本: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> <version>3.2.4</version> <!-- 使用你的Spring Boot版本 --> </dependency> ``` #### ✅ 3. 排除默认Tomcat依赖 在`spring-boot-starter-web`中排除Tomcat: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> ``` #### ✅ 4. 验证仓库配置 在`pom.xml`或`settings.xml`中确保包含Maven中央仓库: ```xml <repositories> <repository> <id>central</id> <url>https://repo.maven.apache.org/maven2</url> </repository> </repositories> ``` #### ✅ 5. 清理Maven缓存 执行以下命令清理本地缓存: ```bash mvn dependency:purge-local-repository mvn clean install -U ``` #### ✅ 6. 完整配置示例 ```xml <dependencies> <!-- Web依赖 (排除Tomcat) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <!-- Jetty依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> <version>${spring-boot.version}</version> </dependency> </dependencies> ``` > **注意**:`${spring-boot.version}`需与父POM中的Spring Boot版本一致[^1] #### ✅ 7. 验证依赖树 检查依赖冲突: ```bash mvn dependency:tree -Dincludes=org.eclipse.jetty ``` 常见错误原因: 1. 缺少版本号(占90%的报错) 2. 未排除Tomcat导致冲突 3. 本地仓库损坏 4. 网络访问限制 --- ### 相关问题 1. **Spring Boot中如何切换Tomcat和Jetty?** 2. 如何在多模块Maven项目中管理Spring Boot依赖版本? 3. Maven依赖解析失败的常见排查方法有哪些? 4. **如何处理Spring Boot中的依赖冲突问题?** 5. Gradle项目如何配置Jetty替代Tomcat?[^2] [^1]: Spring Boot官方文档建议通过父POM管理依赖版本 [^2]: Gradle配置示例参考了依赖管理最佳实践
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值