Spring boot随机端口你都不会还怎么动态扩容

一般情况下每个spring boot工程启动都有固定的端口,但是固定端口不利用服务的动态扩容,如果在一台服务器上需要对同一个服务进行多实例部署,很容易出现端口冲突,那么怎么解决这个问题呢?

random随机端口

在spring boot中,可以通过${random}来生成随机数字,我们可以在配置文件中,这么设置端口:

server.port=${random.int(2000,8000)}

通过random.int方法,指定生成2000~8000的随机端口。这样每次启动的端口都不一样。

多次启动,发现每次的端口都不一致说明配置成功。

注意事项:
这里需要注意spring boot项目启动属性文件的加载顺序,spring boot的属性是由里向外加载,所以最外层的最后被加载,会覆盖里层的属性。
所以如果主动在启动命令中使用–server.port配置了项目的端口号,那么属性文件中配置的随机端口属性就不会生效。

通过System.setProperty设置有效随机端口

上面的方法虽然暂时达到了想要的效果,但是有个问题:如果生成的这个随机端口已经被使用了,那么项目启动就会出现端口冲突。

那么,我们能否通过一个检测机制,让生成的随机端口一定是一个没有被占用的有效的随机端口呢?

有效端口检测原理:

通过建立socket连接,Socket socket = new Socket(Address,port);#address代表主机的IP地址,port代表端口号
如果对该主机的特定端口号能建立一个socket,则说明该主机的该端口在使用。
Socket socket = new Socket(Address,port);#address代表主机的IP地址,port代表端口号
如果对该主机的特定端口号能建立一个socket,则说明该主机的该端口在使用。

实现思路:

通过在项目启动前,获取有效的随机端口并通过System.setProperty将变量设置到系统的全局变量中,这样项目启动时就可以从全局变量中获取到server.port变量的值。
这里的system,系统指的是 JRE (runtime)system,即设置jvm运行时的全局变量。

工具类:

@Slf4j
public class NetUtils {

  /**
   * 测试本机端口是否被使用
   * @param port
   * @return
   */
  public static boolean isLocalPortUsing(int port){
    boolean flag = true;
    try {
      //如果该端口还在使用则返回true,否则返回false,127.0.0.1代表本机
      flag = isPortUsing("127.0.0.1", port);
    } catch (Exception e) {
    }
    return flag;
  }
  /***
   * 测试主机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); //建立一个Socket连接
      flag = true;
    } catch (IOException e) {
      //log.info(e.getMessage(),e);
    }
    return flag;
  }

  //start--end是所要检测的端口范围
  static int start=0;
  static int end=1024;

  /**
   * 由于本机上安装了mysql,采用3306端口去验证
   * @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;
     }
  }

}

项目启动前设置server.port环境变量

/**
 * 开始命令
 */
@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;
          }
       }
     }

     //没有指定端口,则随机生成一个可用的端口
    if(!isServerPort){
       int port = ServerPortUtils.getAvailablePort();
       log.info("current server.port=" + port);
       System.setProperty("server.port",String.valueOf(port));
    }else{//指定了端口,则以指定的端口为准
      log.info("current server.port=" + serverPort.split("=")[1]);
      System.setProperty("server.port",serverPort.split("=")[1]);
    }
  }

}

启动类调用方法:

@SpringBootApplication
@EnableUserClient
@RestController
public class DemoApplication {
  @Autowired
  Environment environment;

  public static void main(String[] args) {
    new StartCommand(args);
    SpringApplication.run(DemoApplication.class, args);
  }
}

通过自定义PropertiesPropertySource属性源实现

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();
  }
}

通过配置在resources/META-INF/spring.factories文件中使用全名注册

org.springframework.boot.env.EnvironmentPostProcessor=com.laowan.demo.command.MyEnvironmentPostProcessor

这样在项目启动后,就会将该属性源加载到Environment中。

总结

1、为什么要设置随机端?主要是为了解决动态扩容时出现端口冲突的问题。
2、怎么获取一个有效的随机端口号
3、spring boot下实现随机端口的三种方式。关于方式三的自定义属性源的实现方式可以多多品味,实践一下,更好的体会属性文件的加载顺序。

到此这篇关于Spring boot随机端口你都不会还怎么动态扩容的文章就介绍到这了,更多相关Spring boot随机端口内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringBoot项目修改访问端口和访问路径的方法

    创建SpringBoot项目,启动后,默认的访问路径即主机IP+默认端口号8080:http://localhost:8080/ 此时,我们就可以访问Controller层的接口了,如:http://localhost:8080/hello package com.springboot.test; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.a

  • Spring Boot修改启动端口的方法

    spring boot是个好东西,可以不用容器直接在main方法中启动,而且无需配置文件,方便快速搭建环境.可是当我们要同时启动2个springboot工程时,就会有问题,有可能会因为8080端口被第一个应用占用而导致第二个应用无法启动,这时就需要修改其中一个工程的启动端口. 1.可以通过实现EmbeddedServletContainerCustomizer接口来实现: public class Application extends SpringBootServletInitializer

  • SpringBoot同时启动不同端口图示解析

    这篇文章主要介绍了SpringBoot同时启动不同端口图示解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.首先右键点击需要同时启动的应用,选择复制配置 或者: 2. 在配置窗口中进行修改 3. 保存后如下,可以右键逐一启动 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们.

  • spring boot如何指定启动端口

    这篇文章主要介绍了spring boot如何指定启动端口,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 spring boot 默认端口为8080 1.修改为指定端口 (1)修改配置文件 src/main/resources/application.properties server.port=8081 (2)通过编码的方式来指定端口 在启动类中添加servletContainer方法 package com.example.demo; imp

  • Spring Boot启动端口修改方法

    spring boot是个好东西,可以不用容器直接在main方法中启动,而且无需配置文件,方便快速搭建环境.可是当我们要同时启动2个springboot工程时,就会有问题,有可能会因为8080端口被第一个应用占用而导致第二个应用无法启动,这时就需要修改其中一个工程的启动端口. 1.可以通过实现EmbeddedServletContainerCustomizer接口来实现: public class Application extends SpringBootServletInitializer

  • 如何设置springboot启动端口

    spring boot是个好东西,可以不用容器直接在main方法中启动,而且无需配置文件,方便快速搭建环境.可是当我们要同时启动2个springboot工程时,就会有问题,有可能会因为8080端口被第一个应用占用而导致第二个应用无法启动,这时就需要修改其中一个工程的启动端口. 可以通过实现EmbeddedServletContainerCustomizer接口来实现: public class Application extends SpringBootServletInitializer im

  • Spring Boot 启动端口如何启动

    Spring Boot 启动端口 Spring Boot 其默认是集成web容器的,启动方式由像普通Java程序一样,main函数入口启动.其内置Tomcat容器或Jetty容器,具体由配置来决定(默认Tomcat).当然你也可以将项目打包成war包,放到独立的web容器中(Tomcat.weblogic等等),当然在此之前你要对程序入口做简单调整. spring boot是个好东西,可以不用容器直接在main方法中启动,而且无需配置文件,方便快速搭建环境.可是当我们要同时启动2个springb

  • SpringBoot项目不占用端口启动的方法

    SpringBoot项目不占用端口启动 现在很多互联网公司或者项目,都使用SpringBoot + SpringCloud,以微服务的形式来提供后台服务.而且既然是微服务,所涉及到的项目就会很多,服务器端口资源就会相当紧张.而且,其实有些项目,如定时任务等,是不需要对外提供服务,也就不需要占用服务器端口的.那么,在SpringBoot项目中,怎么实现呢?其实很简单,如下: @EnableScheduling @SpringBootApplication public class Applicat

  • Spring boot随机端口你都不会还怎么动态扩容

    一般情况下每个spring boot工程启动都有固定的端口,但是固定端口不利用服务的动态扩容,如果在一台服务器上需要对同一个服务进行多实例部署,很容易出现端口冲突,那么怎么解决这个问题呢? random随机端口 在spring boot中,可以通过${random}来生成随机数字,我们可以在配置文件中,这么设置端口: server.port=${random.int(2000,8000)} 通过random.int方法,指定生成2000~8000的随机端口.这样每次启动的端口都不一样. 多次启动

  • 解决Spring Boot项目端口8080被占用的问题

    错误提示: 2018-11-12 21:25:58.422 ERROR 15916 - [ restartedMain] o.s.b.d.LoggingFailureAnalysisReporter : APPLICATION FAILED TO START Description: The Tomcat connector configured to listen on port 8080 failed to start. The port may already be in use or t

  • java Spring Boot的介绍与初体验

    目录 Spring Boot 介绍 系统要求 构建工具 Servlet 容器 初体验 总结 Spring Boot 介绍 Spring Boot用于创建可运行的.独立的.生产级的基于Spring的应用程序.Spring Boot对Spring和第三方库持约定大于配置的观念,以便可以轻松上手.大多数Spring Boot应用程序只需要很少的配置. Spring Boot可以通过使用java -jar或更传统的war包部署来启动Java应用程序,Spring Boot的目标是: 为所有Spring开

  • 浅谈Spring Boot 微服务项目的推荐部署方式

    如果开发过spring boot的程序,应该都知道,使用spring boot官方的maven打包插件(spring-boot-maven-plugin) 来打包,打出来的jar包一般有40M以上. 如果公司的服务器上传带宽不高,那么手动上传一个jar或者jenkins部署一次jar,都是非常痛苦的........ 但是,如果打包的时候不引入lib,那么打出来的jar包一般只有几十k而已,非常小,想怎么传就怎么传......... 本文会提供一个bash启动脚本,只需要稍做更改,即可适应你的程序

  • 详解Spring Boot实战之Restful API的构建

    上一篇文章讲解了通过Spring boot与JdbcTemplate.JPA和MyBatis的集成,实现对数据库的访问.今天主要给大家分享一下如何通过Spring boot向前端返回数据. 在现在的开发流程中,为了最大程度实现前后端的分离,通常后端接口只提供数据接口,由前端通过Ajax请求从后端获取数据并进行渲染再展示给用户.我们用的最多的方式就是后端会返回给前端一个JSON字符串,前端解析JSON字符串生成JavaScript的对象,然后再做处理.本文就来演示一下Spring boot如何实现

  • spring boot打jar包发布的方法

    Spring的项目在spring boot之前一般我都是打成war包发布到tomcat的,但最近使用了spring boot 要打成jar包,一开始不理解为啥有要打成jar,war包不是很好吗? 另外一点是由于现在还不会打jar包,所以感觉没必要.经过一段时间的适应,感觉打jar包是很有必要的,而且发布也很方便了省去了安装tomcat等中间件. 说下如何打jar包把,其实很简单,主要是配置好pom.xml文件就可以了,关键点如下: 一定要写jar. 在<bulid>中添加如下配置: <b

  • 深入Spring Boot之ClassLoader的继承关系和影响

    前言 对spring boot本身启动原理的分析,请参考://www.jb51.net/article/141478.htm Spring boot里的ClassLoader继承关系 可以运行下面提供的demo,分别在不同的场景下运行,可以知道不同场景下的Spring boot应用的ClassLoader继承关系. https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-classloader-context 分三种情况

随机推荐