Takes an opinionated view of building production-ready Spring applications. Spring Boot favors convention over configuration and is designed to get you up and running as quickly as possible.
SpringBoot項(xiàng)目為我們構(gòu)建Spring應(yīng)用帶來(lái)了極大的方便忆矛,同時(shí)SpringBoot在構(gòu)建Spring應(yīng)用方面也做出了很大建樹(shù)
眾所周知龙巨,SpringBoot可以通過(guò)gradle或者maven插件構(gòu)建Executable Jar/War Spring Boot Gradle Plugin Reference Guide
除了傳統(tǒng)方式java -jar myapp.jar
運(yùn)行外土榴,還可以通過(guò)myapp.jar start|stop|restart
運(yùn)行糖权,安裝為systemd服務(wù),通過(guò)同名文件myapp.conf配置運(yùn)行時(shí)參數(shù)等等高級(jí)功能 Installing Spring Boot Applications
講到這里很多童鞋都會(huì)問(wèn)吓揪,這一切都是如何做到的?
將啟動(dòng)腳本嵌入jar
首先,我們創(chuàng)建一個(gè)簡(jiǎn)單的示例
package com.manerfan.springboot.theory;
/**
* @author manerfan
* @date 2018/3/2
*/
public class RunnableApp {
public static void main(String[] args) {
System.out.println("Hello You!");
}
}
使用eclipse或idea或其他工具膳叨,編譯并打包為jar(spring-boot-theory.jar),打包時(shí)選擇main-class為com.manerfan.SpringBoot.theory.RunnableApp
對(duì)于Runnable Jar痘系,總有一個(gè)META-INF/MANIFEST.MF文件菲嘴,記錄Main-Class、Class-Path等信息
我們可以通過(guò)java -jar spring-boot-theory.jar
來(lái)運(yùn)行汰翠,但嘗試直接運(yùn)行spring-boot-theory.jar
時(shí)便會(huì)報(bào)錯(cuò)
這表明龄坪,spring-boot-theory.jar
僅僅為Runnable Jar,而不是Executable Jar
使用shell腳本啟動(dòng)jar
一般情況复唤,我們都會(huì)借助shell腳本來(lái)運(yùn)行我們的jar健田,如下 runJar.sh
#!/bin/sh
JAR="/usr/local/spring-boot-theory.jar"
java=java
if test -n "$JAVA_HOME"; then
java="$JAVA_HOME/bin/java"
fi
exec "$java" -jar $JAR "$@"
exit 1
在此基礎(chǔ)上,我們可以加入更多控制佛纫,以實(shí)現(xiàn)runJar.sh *start | stop | restart*等特性
#!/bin/bash
# chkconfig: 2345 85 85
# description: spring boot theory
# processname: spring-boot-theory
# Created By: manerfan (manerfan.china@gmail.com)
JAR="/usr/local/spring-boot-theory.jar"
PIDFILE=/data/sms-service/smss.pid
java=java
if test -n "$JAVA_HOME"; then
java="$JAVA_HOME/bin/java"
fi
start() {}
stop() {}
restart() {}
status() {}
case "$action" in
start)
start "$@"; exit $?;;
stop)
stop "$@"; exit $?;;
restart)
restart "$@"; exit $?;;
status)
status "$@"; exit $?;;
*)
echo "Usage: $0 {start|stop|force-stop|restart|force-reload|status|run}"; exit 1;
esac
exit 0
可以參考 http://blog.csdn.net/zhanngle...
但這樣也只是通過(guò)shell腳本控制jar的啟動(dòng)停止妓局,如何做到Executable Jar呢?
整合shell腳本與Runnable Jar
同樣呈宇,首先是一段shell腳本 runJar.sh
#!/bin/sh
JAR =`which "$0" 2>/dev/null`
[ $? -gt 0 -a -f "$0" ] && JAR="./$0"
java=java
if test -n "$JAVA_HOME"; then
java="$JAVA_HOME/bin/java"
fi
exec "$java" -jar $JAR "$@"
exit 1
通過(guò)以下語(yǔ)句將shell腳本與jar文件整合到一起 ~劃重點(diǎn)~
cat runJar.sh spring-boot-theory.jar > exec-spring-boot-theory.jar && chmod +x exec-spring-boot-theory.jar
大功告成好爬!
同樣,在此基礎(chǔ)上甥啄,我們可以加入更多控制存炮,以實(shí)現(xiàn)exec-spring-boot-theory.jar *start | stop | restart*等特性
可以參考 https://coderwall.com/p/ssuax...
Spring Boot的實(shí)現(xiàn)原理
SpringBoot項(xiàng)目源碼在https://github.com/spring-pro...,可以對(duì)照查看
我們從 JarWriter 開(kāi)始
public JarWriter(File file, LaunchScript launchScript)
throws FileNotFoundException, IOException {
FileOutputStream fileOutputStream = new FileOutputStream(file);
if (launchScript != null) {
// 將啟動(dòng)腳本寫(xiě)入文件
fileOutputStream.write(launchScript.toByteArray());
// 設(shè)置文件可執(zhí)行屬性
setExecutableFilePermission(file);
}
this.jarOutput = new JarArchiveOutputStream(fileOutputStream);
this.jarOutput.setEncoding("UTF-8");
}
當(dāng)執(zhí)行g(shù)radle build或mvn package時(shí)蜈漓,會(huì)使用JarWriter重新生成jar文件穆桂。JarWrite構(gòu)造函數(shù)中,會(huì)首先將啟動(dòng)腳本寫(xiě)入文件迎变,并設(shè)置文件的可執(zhí)行屬性充尉。
除此之外,JarWriter還有眾多方法衣形,如writeManifest寫(xiě)入manifest文件驼侠、writeNestedLibrary寫(xiě)入第三方依賴(lài)等等,通過(guò)JarWriter以構(gòu)建Executable Jar.
此過(guò)程谆吴,與上述將shell腳本與jar文件整合效果一致倒源。
但是,launchScript又是什么句狼?
public DefaultLaunchScript(File file, Map<?, ?> properties) throws IOException {
// 加載啟動(dòng)腳本
String content = loadContent(file);
this.content = expandPlaceholders(content, properties);
}
private String loadContent(File file) throws IOException {
if (file == null) {
// 默認(rèn)launch.script
return loadContent(getClass().getResourceAsStream("launch.script"));
}
return loadContent(new FileInputStream(file));
}
默認(rèn)的LaunchScript為DefaultLaunchScript笋熬,在構(gòu)造DefaultLaunchScript時(shí),若不指定啟動(dòng)腳本腻菇,則取默認(rèn)的launch.script胳螟,內(nèi)容見(jiàn) launch.script
launch.script實(shí)現(xiàn)較為復(fù)雜昔馋,此處不做解析,launch.script與上述shell腳本的實(shí)現(xiàn)思路基本相同糖耸,同樣實(shí)現(xiàn)了start stop restart等功能秘遏,方便安裝為systemd服務(wù)
不同的是,launch.script會(huì)解析與jar文件同名的conf文件嘉竟,以實(shí)現(xiàn)啟動(dòng)腳本定制化 Customizing a Script When It Runs
如邦危,我們實(shí)現(xiàn)一個(gè)簡(jiǎn)單的web接口
@SpringBootApplication
@RestController
public class WebApp {
public static void main(String[] args) {
SpringApplication.run(WebApp.class, args);
}
@RequestMapping("/")
@GetMapping
public String hello() {
return "Hello You!";
}
}
使用spring-boot-gradle-plugin插件打包,執(zhí)行./spring-boot-theory-1.0.0.jar
舍扰,可以看到輸出
訪問(wèn) http://localhost:8080 可以看到 Hello You! 字樣
若要對(duì)啟動(dòng)參數(shù)倦蚪,如監(jiān)聽(tīng)端口做修改,除了使用java -jar spring-boot-theory-1.0.0.jar --server.port=8000
外边苹,還可以新建同名文件 spring-boot-theroy-1.0.0.conf
陵且,填入內(nèi)容
RUN_ARGS="--server.port=8000"
再次執(zhí)行./spring-boot-theory-1.0.0.jar
監(jiān)聽(tīng)端口由默認(rèn)的8080變?yōu)橹付ǖ?000
conf配置文件可配置的內(nèi)容較多,如使用JAVA_OPTS配置jvm運(yùn)行參數(shù)个束,使用MODE=service
可將程序放入后臺(tái)運(yùn)行等等 Customizing a Script When It Runs
以如下conf配置為例
MODE=service
JAVA_OPTS="-Xms1g -Xmx1g -Dfile.encoding=utf-8"
RUN_ARGS="--server.port=8000"
執(zhí)行./spring-boot-theory-1.0.0.jar start
查看該進(jìn)程運(yùn)行參數(shù)
/usr/bin/java -Dsun.misc.URLClassPath.disableJarChecking=true -Xms1g -Xmx1g -Dfile.encoding=utf-8 -jar /Users/manerfan/Project/learning/javaspring-boot-theory/build/libs/spring-boot-theory-1.0.0.jar --server.port=8000
總結(jié)
SpringBoot實(shí)現(xiàn)ExecutableJar的原理滩报,便是將啟動(dòng)腳本及原有的jar文件(以及第三方依賴(lài)包)寫(xiě)入同一個(gè)文件,并給該文件賦可執(zhí)行權(quán)限播急,結(jié)合conf配置文件脓钾,使RunnableJar變?yōu)镋xecutableJar的同時(shí),得以更加便捷的控制程序的啟動(dòng)/運(yùn)行參數(shù)