场景 代码部署总是需要一个端口,虽然我们可以在配置文件中定义与修改,也可以在部署的时候手动指定。为避免端口冲突何不用代码来为我们自动随机一个端口呢?
方法一 设置server.port=0,当应用启动的时候会自动的分配一个随机端口,但是该方式在注册到Eureka的时候会一个问题:所有实例都使用了同样的实例名(如:Lenovo-test:hello-service:0),这导致只出现了一个实例。所以,我们还需要修改实例ID的定义,让每个实例的ID不同,比如使用随机数来配置实
1 2 server.port =0 eureka.instance.instance-id =${spring.application.name}:${random.int}
方法二 除了上面的方法,实际上我们还可以直接使用random函数来配置server.port。这样就可以指定端口的取值范围,比如:
1 server.port =${random.int[10000,19999]}
由于默认的实例ID会由server.port拼接,而此时server.port设置的随机值会重新取一次随机数,所以使用这种方法的时候不需要重新定义实例ID的规则就能产生不同的实例ID了。
方法三 在《spring cloud 微服务 入门、进阶与实战》中说方法二的配置如果随机的端口刚好已经被使用了,那么启动就会报错。于是通过代码的方式来随机生成一个端口
书中源代码
StartCommand
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 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) { System.out.println("args out ==> " +arg); if (StringUtils.hasText(arg) && arg.startsWith("--server.port" )) { isServerPort = true ; serverPort = arg; break ; } } } if (!isServerPort) { int port = ServerPortUtils.getAvailablePort(); logger.info("no ==== current server.port=" + port); System.setProperty("server.port" , String.valueOf(port)); } else { logger.info("yes ===== current server.port=" + serverPort.split("=" )[1 ]); System.setProperty("server.port" , serverPort.split("=" )[1 ]); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 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); socket.close(); flag = true ; } catch (Exception e) { } return flag; } }
在启动类里:
1 2 3 4 5 6 7 8 @SpringBootApplication public class SpringbootBaseApplication { public static void main (String[] args) { new StartCommand (args); SpringApplication.run(SpringbootBaseApplication.class, args); } }
通过对启动参数进行遍历判断,如果有指定启动端口,后续就不自动生成了;如果没有指定,就通过ServerPortUtils获取一个可以使用的端口,然后设置道环境变量中。在application.properties中通过下面的方式获取端口:
——《spring cloud 微服务 入门、进阶与实战》23页
server.port=${server.port}
项目启动后发现的确重新生成了端口:(但生成了两次目前还不知道为什么)
1 2 22 :26:19.423 [main] INFO com.example.springbootbase.common.StartCommand - current server.port=39401 22 :26:21.550 [restartedMain] INFO com.example.springbootbase.common.StartCommand - current server.port=2204
参考博客:
springboot:随机端口
部分代码源自《spring cloud 微服务 入门、进阶与实战》