在实际开发中,项目的端口都是定好的,通过server.port可以指定端口。当一个服务想要启动多个实例时,就需要改变端口,特别是在微服务中,服务都会注册到注册中心去,为了能够让服务随时都可以扩容,在服务启动的时候能随机生成一个可以使用的端口是最好不过的。
第一种:在配置文件中通过server.port指定。指定的值通过${random}来随机生成
server:
port: ${random.int[2000,8000]}
这种通过配置文件的方式是最简单的,但是如果启动中随机生成的端口已经被占用,那么启动就会报错。
第二种:编写一个启动参数设置类,通过启动参数设置类指定。
1、编写启动参数设置类等相关代码
import com.smile.server.utils.ServerPortUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
/**
* 启动参数设置类
*/
public class StartCommand {
private Logger logger = LoggerFactory.getLogger(StartCommand.class);
public StartCommand(String[] args){
Boolean isServerPort = false;
String serverPort = "";
if (args != null){
for (String arg:args){
if (StringUtils.hasText(arg) && arg.startsWith("--server.port")){
isServerPort = true;
serverPort = arg;
break;
}
}
}
//没有指定端口,则随机生成一个可用的端口
if (!isServerPort){
int port = ServerPortUtils.getAvailablePort();
logger.info("current server.port=" + String.valueOf(port));
System.setProperty("server.port",String.valueOf(port));
}else {
logger.info("current server.port="+ serverPort.split("=")[1]);
System.setProperty("server.port",serverPort.split("=")[1]);
}
}
}
import java.util.Random;
/**
* 随机端口生成类
*/
public class ServerPortUtils {
public static int getAvailablePort(){
int max = 65535;
int min = 2000;
Random random = new Random();
int port = random.nextInt(max)%(max-min+1) + min;
boolean using = NetUtils.isLoclePortUsing(port);
if (using){
return getAvailablePort();
}else {
return port;
}
}
}
import java.net.InetAddress;
import java.net.Socket;
public class NetUtils {
public static boolean isLoclePortUsing(int port){
boolean flag = true;
try {
flag = isPortUsing("127.0.0.1", port);
} catch (Exception e) {
}
return flag;
}
public static boolean isPortUsing(String host,int port) {
boolean flag = false;
try {
InetAddress theAddress = InetAddress.getByName(host);
Socket socket = new Socket(theAddress,port);
flag = true;
} catch (Exception e) {
}
return flag;
}
}
2、在启动类中调用,进行启动参数设置
import com.smile.server.config.StartCommand;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
public class ServerApplication {
public static void main(String[] args) {
//启动参数设置,比如自动生成端口
new StartCommand(args);
SpringApplication.run(ServerApplication.class, args);
System.out.println("项目启动成功!");
}
}
通过启动参数设置类,主要通过对启动参数进行遍历判断,如果有指定端口,后续就不指定了,如果没有指定端口,就通过ServerPortUtils获取一个可以使用的端口,然后设置到环境变量中。注意在存在启动参数设置类的时候,即使在配置文件中指定了项目的端口,配置文件中的端口也不会生效,因此,在存在启动参数设置类的时候,配置文件中server.port的值应当写为下面格式
server:
port: ${server.port}