spring-boot
有一個根據JVM
變量-Dspring.profiles.active
來設置運行時的active profile的功能,可是有些時候咱們也許會不當心忘記設置這個變量,這樣在生產環境中會帶來必定的困擾,因此我想了一個辦法,來給忘記設置-Dspring.profiles.active
的程序員一次「secend chance」。java
先來說一下思路:程序員
-Dspring.profiles.active
,若是已經設置,直接跳轉step3
SpringApplication.run()
代碼以下:spring
spring-boot配置文件(使用了默認profile做爲開發環境):apache
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
的邏輯:tomcat
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 = 10;
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");
final boolean[] started = {false};
Timer timer = new Timer();
if (enableAutomaticallyStart && System.getProperty("os.name").lastIndexOf("Linux") == -1) { //若是當前操做系統環境爲非Linux環境(通常爲開發環境)則automaticallyStartDelay秒後自動設置爲開發環境
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) {
timer.cancel();
started[0] = true;
System.setProperty("spring.profiles.active", "development");
callback.bootRun();
}
}
}, 0, 1000);
}
Scanner scanner = new Scanner(System.in);
Pattern pattern = Pattern.compile("^p|d$");
//若是是Linux系統(通常爲生產環境)則強制等待用戶輸入(通常是忘記設置spring.profiles.active了,這等於給了設置active profile的"second chance")
while (scanner.hasNextLine()) {
if (started[0]) {
break;
}
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");
callback.bootRun();
break;
}
}
} else { //若是已經經過參數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): bash
擴展: 其實在這裏咱們還能夠發散一下思惟,基於spring-boot的應用比起傳統spring應用的一大優點是本身能夠掌控main()
方法,有了這一點,咱們是能玩出不少花樣來的,思路不要被侷限在tomcat
時代了。app
main法在手,天下我有。ide
2017-1-22更新:增長了線程安全的處理spring-boot
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 {
private volatile boolean started;
//用於後續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環境(通常爲開發環境)則automaticallyStartDelay秒後自動設置爲開發環境
System.out.printf("\nSystem will automatically select 'd' in %d seconds.\n", automaticallyStartDelay);
timer.scheduleAtFixedRate(new TimerTask() {
private ThreadLocal<Integer> countDown = ThreadLocal.withInitial(() -> automaticallyStartDelay);
@Override
public void run() {
if (countDown.get() == 0) {
timer.cancel();
started = true;
System.setProperty("spring.profiles.active", "development");
callback.bootRun();
}
countDown.set(countDown.get() - 1);
}
}, 0, 1000);
}
Scanner scanner = new Scanner(System.in);
Pattern pattern = Pattern.compile("^p|d$");
//若是是Linux系統(通常爲生產環境)則強制等待用戶輸入(通常是忘記設置spring.profiles.active了,這等於給了設置active profile的"second chance")
while (scanner.hasNextLine()) {
if (started) {
break;
}
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");
callback.bootRun();
break;
}
}
} else { //若是已經經過參數spring.profiles.active設置了active profile直接啓動
callback.bootRun();
}
}
public void startup(Callback callback) {
startup(this.enableAutomaticallyStart, this.automaticallyStartDelay, callback);
}
}
複製代碼
2017-01-25更新:
補上了 try-with-resource
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 {
private volatile boolean started;
//用於後續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環境(通常爲開發環境)則automaticallyStartDelay秒後自動設置爲開發環境
System.out.printf("\nSystem will automatically select 'd' in %d seconds.\n", automaticallyStartDelay);
timer.scheduleAtFixedRate(new TimerTask() {
private ThreadLocal<Integer> countDown = ThreadLocal.withInitial(() -> automaticallyStartDelay);
@Override
public void run() {
if (countDown.get() == 0) {
timer.cancel();
started = true;
System.setProperty("spring.profiles.active", "development");
callback.bootRun();
}
countDown.set(countDown.get() - 1);
}
}, 0, 1000);
}
try (Scanner scanner = new Scanner(System.in)) {
Pattern pattern = Pattern.compile("^p|d$");
//若是是Linux系統(通常爲生產環境)則強制等待用戶輸入(通常是忘記設置spring.profiles.active了,這等於給了設置active profile的"second chance")
while (scanner.hasNextLine()) {
if (started) {
break;
}
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");
callback.bootRun();
break;
}
}
}
} else { //若是已經經過參數spring.profiles.active設置了active profile直接啓動
callback.bootRun();
}
}
public void startup(Callback callback) {
startup(this.enableAutomaticallyStart, this.automaticallyStartDelay, callback);
}
}
複製代碼