设计思路
- 检查有没有端口占用
- 如果有端口占用可以先使用其他端口及逆行启动
- 等到启动完毕后终止老进程
- 重新创建容器并关联DispatcherServlet
先看代码
package com.test.port;
import org.springframework.beans.factory.annotation.Value;
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.context.ServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ServerSocket;
@SpringBootApplication
@EnableScheduling
public class Main {
public static void main(String[] args) {
String[] newArgs = args;
int defaultPort = 8080;
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(Main.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 servletWebServerFactory = getServletWebServerFactory(run);
((TomcatServletWebServerFactory) servletWebServerFactory).setPort(defaultPort);
WebServer webServer = servletWebServerFactory.getWebServer(invokeSelfInitialize((ServletWebServerApplicationContext) run));
webServer.start();
((ServletWebServerApplicationContext) run).getWebServer().stop();
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
}
}
private static ServletContextInitializer invokeSelfInitialize(ServletWebServerApplicationContext context) {
try {
Method method = ServletWebServerApplicationContext.class.getDeclaredMethod("getSelfInitializer");
method.setAccessible(true);
return (ServletContextInitializer) method.invoke(context);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private static boolean isPortInUse(int port) {
try (ServerSocket ignored = new ServerSocket(port)) {
return false;
} catch (Exception e) {
return true;
}
}
private static ServletWebServerFactory getServletWebServerFactory(ConfigurableApplicationContext context) {
String[] beanNames = context.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
return context.getBean(beanNames[0], ServletWebServerFactory.class);
}
}