Spring boot隨機(jī)端口你都不會(huì)還怎么動(dòng)態(tài)擴(kuò)容
一般情況下每個(gè)spring boot工程啟動(dòng)都有固定的端口,但是固定端口不利用服務(wù)的動(dòng)態(tài)擴(kuò)容,如果在一臺(tái)服務(wù)器上需要對(duì)同一個(gè)服務(wù)進(jìn)行多實(shí)例部署,很容易出現(xiàn)端口沖突,那么怎么解決這個(gè)問(wèn)題呢?
random隨機(jī)端口
在spring boot中,可以通過(guò)${random}來(lái)生成隨機(jī)數(shù)字,我們可以在配置文件中,這么設(shè)置端口:
server.port=${random.int(2000,8000)}
通過(guò)random.int方法,指定生成2000~8000的隨機(jī)端口。這樣每次啟動(dòng)的端口都不一樣。
多次啟動(dòng),發(fā)現(xiàn)每次的端口都不一致說(shuō)明配置成功。


注意事項(xiàng):
這里需要注意spring boot項(xiàng)目啟動(dòng)屬性文件的加載順序,spring boot的屬性是由里向外加載,所以最外層的最后被加載,會(huì)覆蓋里層的屬性。
所以如果主動(dòng)在啟動(dòng)命令中使用–server.port配置了項(xiàng)目的端口號(hào),那么屬性文件中配置的隨機(jī)端口屬性就不會(huì)生效。
通過(guò)System.setProperty設(shè)置有效隨機(jī)端口
上面的方法雖然暫時(shí)達(dá)到了想要的效果,但是有個(gè)問(wèn)題:如果生成的這個(gè)隨機(jī)端口已經(jīng)被使用了,那么項(xiàng)目啟動(dòng)就會(huì)出現(xiàn)端口沖突。
那么,我們能否通過(guò)一個(gè)檢測(cè)機(jī)制,讓生成的隨機(jī)端口一定是一個(gè)沒(méi)有被占用的有效的隨機(jī)端口呢?
有效端口檢測(cè)原理:
通過(guò)建立socket連接,Socket socket = new Socket(Address,port);#address代表主機(jī)的IP地址,port代表端口號(hào)
如果對(duì)該主機(jī)的特定端口號(hào)能建立一個(gè)socket,則說(shuō)明該主機(jī)的該端口在使用。
Socket socket = new Socket(Address,port);#address代表主機(jī)的IP地址,port代表端口號(hào)
如果對(duì)該主機(jī)的特定端口號(hào)能建立一個(gè)socket,則說(shuō)明該主機(jī)的該端口在使用。
實(shí)現(xiàn)思路:
通過(guò)在項(xiàng)目啟動(dòng)前,獲取有效的隨機(jī)端口并通過(guò)System.setProperty將變量設(shè)置到系統(tǒng)的全局變量中,這樣項(xiàng)目啟動(dòng)時(shí)就可以從全局變量中獲取到server.port變量的值。
這里的system,系統(tǒng)指的是 JRE (runtime)system,即設(shè)置jvm運(yùn)行時(shí)的全局變量。
工具類:
@Slf4j
public class NetUtils {
/**
* 測(cè)試本機(jī)端口是否被使用
* @param port
* @return
*/
public static boolean isLocalPortUsing(int port){
boolean flag = true;
try {
//如果該端口還在使用則返回true,否則返回false,127.0.0.1代表本機(jī)
flag = isPortUsing("127.0.0.1", port);
} catch (Exception e) {
}
return flag;
}
/***
* 測(cè)試主機(jī)Host的port端口是否被使用
* @param host
* @param port
* @throws UnknownHostException
*/
public static boolean isPortUsing(String host,int port) {
boolean flag = false;
try {
InetAddress Address = InetAddress.getByName(host);
Socket socket = new Socket(Address,port); //建立一個(gè)Socket連接
flag = true;
} catch (IOException e) {
//log.info(e.getMessage(),e);
}
return flag;
}
//start--end是所要檢測(cè)的端口范圍
static int start=0;
static int end=1024;
/**
* 由于本機(jī)上安裝了mysql,采用3306端口去驗(yàn)證
* @param args
*/
public static void main(String args[]){
int testPost =3306;
if(isLocalPortUsing(testPost)){
System.out.println("端口 "+testPost+" 已被使用");
}else{
System.out.println("端口 "+testPost+"未使用");
}
}
}
public class ServerPortUtils {
/**
* 獲取可用端口
* @return
*/
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.isLocalPortUsing(port);
if(using){
return getAvailablePort();
}else{
return port;
}
}
}
項(xiàng)目啟動(dòng)前設(shè)置server.port環(huán)境變量
/**
* 開(kāi)始命令
*/
@Slf4j
public class StartCommand {
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;
}
}
}
//沒(méi)有指定端口,則隨機(jī)生成一個(gè)可用的端口
if(!isServerPort){
int port = ServerPortUtils.getAvailablePort();
log.info("current server.port=" + port);
System.setProperty("server.port",String.valueOf(port));
}else{//指定了端口,則以指定的端口為準(zhǔn)
log.info("current server.port=" + serverPort.split("=")[1]);
System.setProperty("server.port",serverPort.split("=")[1]);
}
}
}
啟動(dòng)類調(diào)用方法:
@SpringBootApplication
@EnableUserClient
@RestController
public class DemoApplication {
@Autowired
Environment environment;
public static void main(String[] args) {
new StartCommand(args);
SpringApplication.run(DemoApplication.class, args);
}
}
通過(guò)自定義PropertiesPropertySource屬性源實(shí)現(xiàn)
public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
//MapPropertySource
Properties properties = new Properties();
properties.put("server.port", ServerPortUtils.getAvailablePort());
System.out.println(properties.get("server.port"));
PropertiesPropertySource source = new PropertiesPropertySource("myCustom", properties);
environment.getPropertySources().addLast(source);
//environment.getPropertySources().addAfter();
}
}
通過(guò)配置在resources/META-INF/spring.factories文件中使用全名注冊(cè)
org.springframework.boot.env.EnvironmentPostProcessor=com.laowan.demo.command.MyEnvironmentPostProcessor
這樣在項(xiàng)目啟動(dòng)后,就會(huì)將該屬性源加載到Environment中。

總結(jié)
1、為什么要設(shè)置隨機(jī)端?主要是為了解決動(dòng)態(tài)擴(kuò)容時(shí)出現(xiàn)端口沖突的問(wèn)題。
2、怎么獲取一個(gè)有效的隨機(jī)端口號(hào)
3、spring boot下實(shí)現(xiàn)隨機(jī)端口的三種方式。關(guān)于方式三的自定義屬性源的實(shí)現(xiàn)方式可以多多品味,實(shí)踐一下,更好的體會(huì)屬性文件的加載順序。
到此這篇關(guān)于Spring boot隨機(jī)端口你都不會(huì)還怎么動(dòng)態(tài)擴(kuò)容的文章就介紹到這了,更多相關(guān)Spring boot隨機(jī)端口內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot文件上傳出現(xiàn)找不到指定系統(tǒng)路徑的解決
這篇文章主要介紹了Springboot文件上傳出現(xiàn)找不到指定系統(tǒng)路徑的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
SpringBoot Security密碼加鹽實(shí)例
這篇文章主要為打擊介紹了SpringBoot Security密碼加鹽實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
spring aop execution表達(dá)式的用法
這篇文章主要介紹了spring aop execution表達(dá)式的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
spring Boot打包部署到遠(yuǎn)程服務(wù)器的tomcat中
這篇文章主要給大家介紹了關(guān)于spring Boot打包部署到遠(yuǎn)程服務(wù)器的tomcat中的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12
基于SpringBoot+Avue實(shí)現(xiàn)短信通知功能
Avue是基于vue和element-ui的快速開(kāi)發(fā)框架 ,它的核心是數(shù)據(jù)驅(qū)動(dòng)UI的思想,讓我們從繁瑣的crud開(kāi)發(fā)中解脫出來(lái),本文將給大家介紹一下使用SpringBoot+Avue實(shí)現(xiàn)短信通知功能,文中有詳細(xì)的代碼示例,需要的朋友可以參考下2023-09-09
1秒鐘實(shí)現(xiàn)Springboot?替換/寫入?word文檔里面的文字、圖片功能
這篇文章主要介紹了Springboot?替換/寫入?word文檔里面的文字、圖片,1秒鐘實(shí)現(xiàn),本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12
Java跨session實(shí)現(xiàn)token接口測(cè)試過(guò)程圖解
這篇文章主要介紹了Java跨session實(shí)現(xiàn)token接口測(cè)試過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04

