转载

为基于spring-boot的应用添加根据运行时操作系统环境来提示用户选择active profile的功能

spring-boot 有一个根据 JVM 变量 -Dspring.profiles.active 来设置运行时的active profile的功能,但是有些时候我们也许会不小心忘记设置这个变量,这样在生产环境中会带来一定的困扰,所以我想了一个办法,来给忘记设置 -Dspring.profiles.active 的程序员一次“secend chance”。

为基于spring-boot的应用添加根据运行时操作系统环境来提示用户选择active profile的功能

先来讲一下思路:

  • step0 约定好profiles的命名,“development”代表开发环境(也可以将默认的profile设为开发环境),“production”代表生产环境
  • step1 判断是否设置了 -Dspring.profiles.active ,如果已经设置,直接跳转 step3
  • step2 判断当前操作系统环境,如果不是Linux环境则认定为开发环境,自动倒计时激活开发的profile;如果是Linux环境则认定为生产环境,输出选择profile的控制台信息,并等待用户控制台输入进行选择,并依据用户选择来激活profile
  • step3 SpringApplication.run()

代码如下:

spring-boot配置文件(使用了默认profile作为开发环境):

spring:
  application:
    name: comchangyoueurekaserver #注意命名要符合RFC 2396,否则会影响服务发现 详见https://stackoverflow.com/questions/37062828/spring-cloud-brixton-rc2-eureka-feign-or-rest-template-configuration-not-wor

server:
  port: 8001

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}

---
spring:
  profiles: production
  application:
    name: comchangyoueurekaserver

server:
  port: 8001

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}

BootStarter 封装了 step1 - step3 的逻辑:

import org.apache.commons.lang3.StringUtils;

import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;
import java.util.regex.Pattern;

public class BootStarter {

    //用于后续Spring Boot操作的回调
    public interface Callback {
        void bootRun();
    }

    private boolean enableAutomaticallyStart = true;
    private int automaticallyStartDelay = 3;

    public boolean isEnableAutomaticallyStart() {
        return enableAutomaticallyStart;
    }

    public void setEnableAutomaticallyStart(boolean enableAutomaticallyStart) {
        this.enableAutomaticallyStart = enableAutomaticallyStart;
    }

    public int getAutomaticallyStartDelay() {
        return automaticallyStartDelay;
    }

    public void setAutomaticallyStartDelay(int automaticallyStartDelay) {
        this.automaticallyStartDelay = automaticallyStartDelay;
    }

    public void startup(boolean enableAutomaticallyStart, int automaticallyStartDelay, Callback callback) {
        if (StringUtils.isBlank(System.getProperty("spring.profiles.active"))) { //如果没有通过参数spring.profiles.active设置active profile则让用户在控制台自己选择
            System.out.println("***Please choose active profile:***/n/tp: production/n/td: development");

            Timer timer = new Timer();
            if (enableAutomaticallyStart && System.getProperty("os.name").lastIndexOf("Linux") == -1) { //如果当前操作系统环境为非Linux环境(一般为开发环境)则automaticallyChooseThreshold秒后自动选择d
                System.out.printf("/nSystem will automatically select 'd' in %d seconds./n", automaticallyStartDelay);
                final int[] count = {automaticallyStartDelay};
                timer.scheduleAtFixedRate(new TimerTask() {
                    @Override
                    public void run() {
                        if (count[0]-- == 0) {
                            System.setProperty("spring.profiles.active", System.getProperty("os.name").lastIndexOf("Linux") == -1 ? "development" : "production");
                            timer.cancel();
                            callback.bootRun();
                        }
                    }
                }, 0, 1000);
            }

            Pattern pattern = Pattern.compile("^p|d$");
            Scanner scanner = new Scanner(System.in);

            //如果是Linux系统(一般为生产环境)则强制等待用户输入(一般是忘记设置spring.profiles.active了,这等于给了设置active profile的"second chance")
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                if (!pattern.matcher(line).find()) {
                    System.out.println("INVALID INPUT!");
                } else {
                    timer.cancel();
                    System.setProperty("spring.profiles.active", line.equals("d") ? "development" : "production");
                    break;
                }
            }
        }

        //如果已经通过参数spring.profiles.active设置了active profile直接启动
        callback.bootRun();
    }

    public void startup(Callback callback) {
        startup(this.enableAutomaticallyStart, this.automaticallyStartDelay, callback);
    }
}

main():

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.context.ApplicationContext;

@EnableEurekaServer
@SpringBootApplication
public class App {

    private static final Logger LOGGER = LoggerFactory.getLogger(App.class);

    public static void main(String[] args) {
        new BootStarter().startup(() -> {
            ApplicationContext applicationContext = SpringApplication.run(App.class, args);
            for (String activeProfile : applicationContext.getEnvironment().getActiveProfiles()) {
                LOGGER.warn("***Running with profile: {}***", activeProfile);
            }
        });
    }
}

运行效果(开发环境Mac OS):

为基于spring-boot的应用添加根据运行时操作系统环境来提示用户选择active profile的功能
原文  https://juejin.im/post/5a583ea66fb9a01c9e45e488
正文到此结束
Loading...