Springboot 代码更新
117人浏览 / 0人评论
参考
https://mp.weixin.qq.com/s/fG8MnzLDangO0Zkime6RMA
方法一
新代码先用其他端口启动,启动完毕后,更改 nginx 的转发地址,然后停止老代码。
方法二
原理:
- SpringBoot内嵌Servlet容器
- DispatcherServlet是如何传递给Servlet容器的
操作过程:
- 判断端口是否占用
- 占用则先通过其他端口启动
- 等待启动完毕后终止老进程
- 重新创建容器实例并且关联DispatcherServlet
@SpringBootApplication()
@EnableScheduling
public class WebMainApplication {
public static void main(String[] args) {
String[] newArgs = args.clone();
int defaultPort = 8088;
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=9090";
needChangePort = true;
}
ConfigurableApplicationContext run = SpringApplication.run(WebMainApplication.class, newArgs);
if (needChangePort) {
String command = String.format("lsof -i :%d | grep LISTEN | awk '{print $2}' | xargs kill -9", 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);
}
}
全部评论