当前位置: 首页 > news >正文

spring boot实现不停机更新

主要实现思路:发布新的应用程序(与原端口不同),启动成功后,将原端口进行优雅关闭,同时将应用程序端口动态切换至原端口

application.yml

server:port: 8000shutdown: graceful

DatapickCliApplication

package com.zy.datapickcli;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.boot.web.servlet.ServletContextInitializerBeans;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.ConfigurableApplicationContext;import java.io.IOException;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.util.Collection;/*** 启动程序** @author javachen*/
@SpringBootApplication
public class DatapickCliApplication
{public static void main(String[] args) {String[] newArgs = args.clone();int defaultPort = 8000;boolean needChangePort = false;if (isPortInUse(defaultPort)) {newArgs = new String[args.length + 1];System.arraycopy(args, 0, newArgs, 0, args.length);newArgs[newArgs.length - 1] = "--server.port=8100";needChangePort = true;}ConfigurableApplicationContext run = SpringApplication.run(DatapickCliApplication.class, newArgs);if (needChangePort) {String command = String.format("lsof -i :%d | grep LISTEN | awk '{print $2}' | xargs kill -2", defaultPort);try {Runtime.getRuntime().exec(new String[]{"sh", "-c", command}).waitFor();while (isPortInUse(defaultPort)) {}ServletWebServerFactory webServerFactory = getWebServerFactory(run);((TomcatServletWebServerFactory) webServerFactory).setPort(defaultPort);WebServer webServer = webServerFactory.getWebServer(invokeSelfInitialize(((ServletWebServerApplicationContext) run)));webServer.start();((ServletWebServerApplicationContext) run).getWebServer().stop();} catch (IOException | InterruptedException ignored) {}}}private static ServletContextInitializer invokeSelfInitialize(ServletWebServerApplicationContext context) {try {Method method = ServletWebServerApplicationContext.class.getDeclaredMethod("getSelfInitializer");method.setAccessible(true);return (ServletContextInitializer) method.invoke(context);} catch (Throwable e) {throw new RuntimeException(e);}}private static boolean isPortInUse(int port) {try (ServerSocket serverSocket = new ServerSocket(port)) {return false;} catch (IOException e) {return true;}}protected static Collection<ServletContextInitializer> getServletContextInitializerBeans(ConfigurableApplicationContext context) {return new ServletContextInitializerBeans(context.getBeanFactory());}private static ServletWebServerFactory getWebServerFactory(ConfigurableApplicationContext context) {String[] beanNames = context.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);return context.getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);}}

http://www.mrgr.cn/news/54407.html

相关文章:

  • 【Spring篇】Spring中的Bean管理
  • Reflection 70B乌龙事件始末:揭开“最强大模型”背后的真相
  • 工信部绿色工厂、绿色设计产品、绿色供应链企业、绿色园区名单(2017-2022年)
  • 07 P1088 [NOIP2004 普及组] 火星人
  • 脉冲扩散模型
  • 使用 Elastic、OpenTelemetry 和 Langtrace 观察 Langchain 应用程序
  • Fake Location 限制解除(运动世界校园,keep......)
  • 笔记本使用虚拟机,使用Ubuntu打开摄像头
  • ICM20948 DMP代码详解(89)
  • AJAX——POST 设置请求头信息
  • nginx(负载均衡)+web实例
  • Python | Leetcode Python题解之第495题提莫攻击
  • 基于Springboot+Vue的资源分享系统(含源码数据库)
  • Repo工具详解
  • 【黑马Redis原理篇】Redis网络模型
  • 基于SpringBoot的在线汽车票预订平台
  • 新手入门之初识maven
  • Burp Suite Professional 2024.9 for macOS x64 ARM64 - 领先的 Web 渗透测试软件
  • LeetCode 每日一题 2024/10/14-2024/10/20
  • A股反弹行情结束了吗?