1、Spring Boot內置web
Spring Boot 其默認是集成web容器的,啓動方式由像普通Java程序一樣,main函數入口啓動。其內置Tomcat容器或Jetty容器,具體由配置來決定(默認Tomcat)。當然你也可以將項目打包成war包,放到獨立的web容器中(Tomcat、weblogic等等),當然在此之前你要對程序入口做簡單調整。
對server的幾個常用的配置做個簡單說明:
- # 項目contextPath,一般在正式發佈版本中,我們不配置
- server.context-path=/myspringboot
- # 錯誤頁,指定發生錯誤時,跳轉的URL。請查看BasicErrorController源碼便知
- server.error.path=/error
- # 服務端口
- server.port=9090
- # session最大超時時間(分鐘),默認爲30
- server.session-timeout=60
- # 該服務綁定IP地址,啓動服務器時如本機不是該IP地址則拋出異常啓動失敗,只有特殊需求的情況下才配置
- # server.address=192.168.16.11
Tomcat
Tomcat爲Spring Boot的默認容器,下面是幾個常用配置:
pom.xml依賴配置:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<!--<scope>provided</scope>-->
</dependency>
- # tomcat最大線程數,默認爲200
- server.tomcat.max-threads=800
- # tomcat的URI編碼
- server.tomcat.uri-encoding=UTF-8
- # 存放Tomcat的日誌、Dump等文件的臨時文件夾,默認爲系統的tmp文件夾(如:C:\Users\Shanhy\AppData\Local\Temp)
- server.tomcat.basedir=H:/springboot-tomcat-tmp
- # 打開Tomcat的Access日誌,並可以設置日誌格式的方法:
- #server.tomcat.access-log-enabled=true
- #server.tomcat.access-log-pattern=
- # accesslog目錄,默認在basedir/logs
- #server.tomcat.accesslog.directory=
- # 日誌文件目錄
- logging.path=H:/springboot-tomcat-tmp
- # 日誌文件名稱,默認爲spring.log
- logging.file=myapp.log
如果你要選擇Jetty,也非常簡單,就是把pom中的tomcat依賴排除,並加入Jetty容器的依賴,如下:
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- <exclusions>
- <exclusion>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-tomcat</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-jetty</artifactId>
- </dependency>
- <dependencies>
項目構建我們使用Maven或Gradle,這將使項目依賴、jar包管理、以及打包部署變的非常方便。
在spring boot裏,很吸引人的一個特性是可以直接把應用打包成爲一個jar/war,然後這個jar/war是可以直接啓動的,不需要另外配置一個Web Server。單獨的JAR包,然後通過java -jar <name>.jar
命令運行。
1.1 Maven
SpringBootMaven插件爲Maven提供SpringBoot支持,它允許你打包可執行jar或war存檔,然後就地運行應用。爲了使用
它,你需要使用Maven 3.2(或更高版本)。
Maven用戶可以繼承spring-boot-starter-parent項目來獲取合適的默認設置。該父項目提供以下特性:
1、默認編譯級別爲Java 1.6
2、源碼編碼爲UTF-8
3、一個依賴管理節點,允許你省略普通依賴的 <version>標籤,繼承自 spring-boot-dependenciesPOM。
合適的資源過濾
4、合適的插件配置(exec插件,surefire,Git commitID,shade)
5、針對 application.properties和application.yml 的資源過濾
6、最後一點:由於默認配置文件接收Spring風格的佔位符( ${...} ),Maven filtering改用@..@ 佔位符(你可以使用Maven屬性 resource.delimiter來覆蓋它)。
- <!-- Inherit defaults from Spring Boot -->
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>1.3.0.BUILD-SNAPSHOT</version>
- </parent>
注:你應該只需要在該依賴上指定Spring Boot版本。如他的starters,你可以放心的省略版本號。
Maven配置。
如果你不使用 spring-boot-starter-parent ,通過使用一個scope=import 的依賴,你仍能獲取到依賴管理的好處:
- <dependencyManagement>
- <dependencies>
- <dependency>
- <!-- Import dependency management from Spring Boot -->
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-dependencies</artifactId>
- <version>1.3.0.BUILD-SNAPSHOT</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
spring-boot-starter-parent選擇相當保守的Java兼容策略。如果你遵循我們的建議,使用最新的Java版本,你可以添加一
個 java.version屬性:
<properties>
<java.version>1.8</java.version>
</properties>
1.5 使用Spring Boot Maven插件
SpringBoot包含一個Maven插件,它可以將項目打包成一個可執行jar。如果想使用它,你可以將該插件添加到<plugins>節
點處:
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <!-- ... -->
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- <version>1.3.0.BUILD-SNAPSHOT</version>
- <executions>
- <execution>
- <goals>
- <goal>repackage</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
- </project>
注:如果使用Spring-Boot-tarter-parent pom,你只需要添加該插件而無需配置它,除非你想改變定義在partent中的設置。
該配置會在Maven生命週期的 package階段重新打包一個jar或war。下面的示例顯示在target目錄下既有重新打包後的jar,
也有原始的jar:
1.6 linux下打包方法:
使用 mvn clean package 命令打包如果還沒有安裝maven :
yum -y install apache-maven
wget http://apache.fayea.com/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz
tar zxvf apache-maven-3.3.9-bin.tar.gz
設置環境變量:
MVN_HOME=/usr/local/app/apache-maven-3.3.9
export PATH=$PATH:$MVN_HOME/bin
然後可以使用以下命令編譯:
mvn clean package
可以追加參數 -Dmaven.test.skip=true 跳過測試。
- $mvn package
- $ls target/*.ja
1.6 使用Eclipse下打包方法:
打開maven插件的maven package,就可以打包了:
打包出來的文件:
如果不包含像上面那樣的<execution/>,你可以自己運行該插件(但只有在package目標也被使用的情況)。例如:
- $ mvn package spring-boot:repackage
- $ ls target/*.jar
target/myproject-1.0.0.jar target/myproject-1.0.0.jar.original
如果使用一個里程碑或快照版本,你還需要添加正確的pluginRepository元素:
- <pluginRepositories>
- <pluginRepository>
- <id>spring-snapshots</id>
- <url>http://repo.spring.io/snapshot</url>
- </pluginRepository>
- <pluginRepository>
- <id>spring-milestones</id>
- <url>http://repo.spring.io/milestone</url>
- </pluginRepository>
- </pluginRepositories>
打包可執行jar和war文件
一旦spring-boot-maven-plugin被包含到你的pom.xml中,它就會自動嘗試使用spring-boot:repackage目標重寫存檔以使它們能夠執行。爲了構建一個jar或war,你應該使用常規的packaging元素配置你的項目:
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <!-- ... -->
- <packaging>jar</packaging>
- <!-- ... -->
- </project>
生成的存檔在 package 階段會被SpringBoot增強。你想啓動的main類即可以通過指定一個配置選項,也可以通過爲manifest添加一個Main-Class屬性這種常規的方式實現。如果你沒有指定一個main類,該插件會搜索帶有publicstaticvoidmain(String[]args)方法的類。
爲了構建和運行一個項目的artifact,你可以輸入以下命令:
- $ mvn package
- $ java -jar target/spring-boot01-1.0-SNAPSHOT.jar
這種方式,只要控制檯關閉,服務就不能訪問了。下面我們使得 jar 包在後臺運行:
java -jar spring-boot01-1.0-SNAPSHOT.jar > log.file 2>&1 &
爲了構建一個即是可執行的,又能部署到一個外部容器的war文件,你需要標記內嵌容器依賴爲"provided",例如:
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <!-- ... -->
- <packaging>war</packaging>
- <!-- ... -->
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-tomcat</artifactId>
- <scope>provided</scope>
- </dependency>
- <!-- ... -->
- </dependencies>
- </project>
4、打包爲單個jar時,spring boot的啓動方式
maven打包之後,會生成兩個jar文件:
demo-0.0.1-SNAPSHOT.jar
demo-0.0.1-SNAPSHOT.jar.original
其中demo-0.0.1-SNAPSHOT.jar.original是默認的maven-jar-plugin生成的包。
demo-0.0.1-SNAPSHOT.jar是spring boot maven插件生成的jar包,裏面包含了應用的依賴,以及spring boot相關的類。下面稱之爲fat jar。
先來查看spring boot打好的包的目錄結構(不重要的省略掉):
- ├── META-INF
- │ ├── MANIFEST.MF
- ├── application.properties
- ├── com
- │ └── example
- │ └── SpringBootDemoApplication.class
- ├── lib
- │ ├── aopalliance-1.0.jar
- │ ├── spring-beans-4.2.3.RELEASE.jar
- │ ├── ...
- └── org
- └── springframework
- └── boot
- └── loader
- ├── ExecutableArchiveLauncher.class
- ├── JarLauncher.class
- ├── JavaAgentDetector.class
- ├── LaunchedURLClassLoader.class
- ├── Launcher.class
- ├── MainMethodRunner.class
- ├── ...
依次來看下這些內容。
MANIFEST.MF
- Manifest-Version: 1.0
- Start-Class: com.example.SpringBootDemoApplication
- Implementation-Vendor-Id: com.example
- Spring-Boot-Version: 1.3.0.RELEASE
- Created-By: Apache Maven 3.3.3
- Build-Jdk: 1.8.0_60
- Implementation-Vendor: Pivotal Software, Inc.
- Main-Class: org.springframework.boot.loader.JarLauncher
可以看到有Main-Class是org.springframework.boot.loader.JarLauncher ,這個是jar啓動的Main函數。
還有一個Start-Class是com.example.SpringBootDemoApplication,這個是我們應用自己的Main函數
- @SpringBootApplication
- public class SpringBootDemoApplication {
- public static void main(String[] args) {
- SpringApplication.run(SpringBootDemoApplication.class, args);
- }
- }
com/example 目錄
這下面放的是應用的.class文件。
lib目錄
這裏存放的是應用的Maven依賴的jar包文件。
比如spring-beans,spring-mvc等jar。
org/springframework/boot/loader 目錄
這下面存放的是Spring boot loader的.class文件。
啓動:
我們直接啓動:java -jar demo-0.0.1-SNAPSHOT.jar
5、Maven添加本地Jar包
我們有時候項目依賴外部的jar,我們使用Eclipse開發的時候我們直接通過build path添加jar就可以,但是使用mvn 打包的時候就會缺少這個包。
1. 使用system scope
我們直接引入rabbitmq-client.jar。這個方式比較靈活,到新的服務器上,無需做額外的操作。
- <dependency>
- <groupId>rabbitmq.client</groupId>
- <artifactId>rabbitmq.client</artifactId>
- <version>3.0</version>
- <scope>system</scope>
- <systemPath>${basedir}/src/main/WEB-INF/lib/rabbitmq-client.jar</systemPath>
- </dependency>
2、${basedir}就是項目根目錄
2. 將jar包安裝到本地repository中
這個需要在新機器上執行mvn install:install-file命令。
- mvn install:install-file
- -Dfile= jar文件所存放的地址
- -DgroupId= jar文件所屬的group:包名
- -DartifactId= jar的項目名 名稱,一般就是去掉後綴的文件名
- -Dversion=版本號
- -Dpackaging=jar:此包的打包形式,就是jar
- -DgeneratePom=true
mvn install:install-file -Dfile=D:\JAR_LIB\rabbitmq-client.jar -DgroupId=com.rabbitmq -DartifactId=client -Dversion=3.5.0 -Dpackaging=jar -DgeneratePom=true -DcreateChecksum=true
在項目中引用:
- <dependency>
- <groupId>com.rabbitmq</groupId>
- <artifactId>client</artifactId>
- <version>3.5.0</version>
- </dependency>
3、添加 in project repository
設置項目的庫目錄
<repository>
<id>in-project</id>
<name>In Project Repo</name>
<url>file://${project.basedir}/lib</url>
</repository>
添加依賴:
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>client</artifactId>
<version>3.5.0</version>
</dependency>
jar包及路徑必須嚴格遵循格式:
/groupId/artifactId/version/artifactId-verion.jar
本例中: lib/com/rabbitmq/client/3.5.0/rabbitmq-client-3.5.0.jar
6、部署到javaEE容器
- public class SpringBootSampleApplication extends SpringBootServletInitializer{
- private static final Logger logger = LoggerFactory.getLogger(SpringBootSampleApplication.class);
- @Override
- protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
- return builder.sources(this.getClass());
- }
- }
- <!-- <packaging>jar</packaging> -->
- <packaging>war</packaging>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- <exclusions>
- <exclusion>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-tomcat</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
7、熱部署
在我們開發過程中,我們需要經常修改,爲了避免重複啓動項目,我們可以啓用熱部署。Spring-Loaded項目提供了強大的熱部署功能,添加/刪除/修改 方法/字段/接口/枚舉 等代碼的時候都可以熱部署,速度很快,很方便。
想在Spring Boot中使用該功能非常簡單,就是在spring-boot-maven-plugin插件下面添加依賴:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.5.RELEASE</version>
</dependency>
</dependencies>
添加以後,通過mvn spring-boot:run啓動就支持熱部署了。
注意:使用熱部署的時候,需要IDE編譯類後才能生效,你可以打開自動編譯功能,這樣在你保存修改的時候,類就自動重新加載了。
8、使用Profile區分環境
application.properties區分環境
spring boot 可以在 “配置文件”、“Java代碼類”、“日誌配置” 中來配置profile區分不同環境執行不同的結果
1、配置文件
使用配置文件application.yml 和 application.properties 有所區別
以application.properties 爲例,通過文件名來區分環境 application-{profile}.properties
application.properties
app.name=MyApp
server.port=8080
spring.profiles.active=dev
application-dev.properties
server.port=8081
application-stg.properties
server.port=8082
在啓動程序的時候通過添加 –spring.profiles.active={profile} 來指定具體使用的配置
例如我們執行 java -jar demo.jar –spring.profiles.active=dev 那麼上面3個文件中的內容將被如何應用?
Spring Boot 會先加載默認的配置文件,然後使用具體指定的profile中的配置去覆蓋默認配置。
app.name 只存在於默認配置文件 application.properties 中,因爲指定環境中不存在同樣的配置,所以該值不會被覆蓋
server.port 默認爲8080,但是我們指定了環境後,將會被覆蓋。如果指定stg環境,server.port 則爲 8082
spring.profiles.active 默認指定dev環境,如果我們在運行時指定 –spring.profiles.active=stg 那麼將應用stg環境,最終 server.port 的值爲8082
Maven環境配置
項目工程統一使用maven的profile插件定義不同的項目構建環境(dev, alpha, beta, prod),通過filter插件爲不同環境下的配置項注入對應的參數值來實現動態配置目標。
2.3.1定義profile
在POM.xml中配置四個profile,對應項目所處的四個不同的環境-dev, alpha, beta, prod, profile的id屬性即爲每個環境賦予一個唯一的標示,元素的內容則是以key-value的形式出現的鍵值對,如我們定義了一個變量,其值在不同的環境下(不同id)被賦予了不同的值(dev, test, pre-prod, prod),要激活不同的環境打包,我們可以在命令行通過mvn package –P${profileId}來讓其運行,爲了開發便利,默認激活的是dev開發環境,即開發人員不需要通過命令行手動輸入-p參數也能運行dev環境的打包。
<profile>
<!-- 本地參數 -->
<id>dev</id>
<properties>
<server.port>8081</server.port>
<server.address>0.0.0.0</server.address>
<profileActive>dev</profileActive>
</properties>
<build>
<filters>
<filter>
<groupId>${basedir}/src/main/resources/dev.properties</groupId>
</filter>
</profile>
9、創建一個Linux 應用的sh腳本
下面幾個腳本僅供參考:
打包:clean.sh
- #0、check user
- TIME_STAMP=`date +%Y%m%d%H%M`
- WHO=`whoami`
- if [ "$WHO" != 'www' ]; then
- echo 'current user is not www'
- echo 'exit'
- exit
- fi
- CODE_HOME=/home/www/app
- PROJECTNAME=qrealtime
- cd $CODE_HOME/$PROJECTNAME
- git pull
- mvn clean package
- pid=`ps -ef |grep $PROJECTNAME |grep -v "grep" |awk '{print $2}' `
- if [ $pid != "" ]; then
- echo "App is running and pid=$pid"
- else
- echo "App is not running."
- fi
start.sh
- #0、check user
- TIME_STAMP=`date +%Y%m%d%H%M`
- WHO=`whoami`
- if [ "$WHO" != 'www' ]; then
- echo 'current user is not www'
- echo 'exit'
- exit
- fi
- CODE_HOME=/home/www/app
- PROJECTNAME=qrealtime
- cd $CODE_HOME/$PROJECTNAME
- pid=`ps -ef |grep $PROJECTNAME |grep -v "grep" |awk '{print $2}'`
- if [ $pid ]; then
- echo "App is running and pid=$pid"
- else
- nohup java -jar $CODE_HOME/$PROJECTNAME/target/$<span style="font-family: 'microsoft yahei';">PROJECTNAME</span><span style="font-family: 'microsoft yahei';">-0.0.1-SNAPSHOT.jar > /dev/null 2>&1 &</span>
- fi
stop.sh
- #0、check user
- TIME_STAMP=`date +%Y%m%d%H%M`
- WHO=`whoami`
- if [ "$WHO" != 'www' ]; then
- echo 'current user is not www'
- echo 'exit'
- exit
- fi
- CODE_HOME=/home/www/app
- PROJECTNAME=qrealtime
- cd $CODE_HOME/$PROJECTNAME
- pid=`ps -ef |grep $PROJECTNAME |grep -v "grep" |awk '{print $2}' `
- if [ $pid ]; then
- echo "App is running and pid=$pid"
- kill -9 $pid
- if [[ $? -eq 0 ]];then
- echo "sucess to stop $PROJECTNAME "
- else
- echo "fail to stop $PROJECTNAME "
- fi
- fi
- #0、check user
- TIME_STAMP=`date +%Y%m%d%H%M`
- WHO=`whoami`
- if [ "$WHO" != 'www' ]; then
- echo 'current user is not www'
- echo 'exit'
- exit
- fi
- CODE_HOME=/home/www/app
- PROJECTNAME=qrealtime
- cd $CODE_HOME/$PROJECTNAME
- pid=`ps -ef |grep $PROJECTNAME |grep -v "grep" |awk '{print $2}' `
- if [ $pid ]; then
- echo "App is running and pid=$pid"
- kill -9 $pid
- fi
- nohup java -jar $CODE_HOME/$PROJECTNAME/target/$PROJECTNAME-0.0.1-SNAPSHOT.jar > /dev/null 2>&1 &
10、Spring Boot應用的docker化
首先看Spring Boot應用程序的docker化,由於Spring Boot內嵌了tomcat、Jetty等容器,因此我們對docker鏡像的要求就是需要java運行環境。我的應用代碼的的Dockerfile文件如下:
#基礎鏡像:倉庫是java,標籤用8u66-jdk
FROM java:8u66-jdk
#當前鏡像的維護者和聯繫方式
MAINTAINER duqi [email protected]
#將打包好的spring程序拷貝到容器中的指定位置
ADD target/bookpub-0.0.1-SNAPSHOT.jar /opt/bookpub-0.0.1-SNAPSHOT.jar
#容器對外暴露8080端口
EXPOSE 8080
#容器啓動後需要執行的命令
CMD java -Djava.security.egd=file:/dev/./urandom -jar /opt/bookpub-0.0.1-SNAPSHOT.jar
因爲目前的示例程序比較簡單,這個dockerfile並沒有在將應用程序的數據存放在宿主機上。如果你的應用程序需要寫文件系統,例如日誌,最好利用VOLUME /tmp
命令,這個命令的效果是:在宿主機的/var/lib/docker目錄下創建一個臨時文件並把它鏈接到容器中的/tmp目錄。
把這個Dockerfile放在項目的根目錄下即可,後續通過docker-compose build
統一構建:基礎鏡像是隻讀的,然後會在該基礎鏡像上增加新的可寫層來供我們使用,因此java鏡像只需要下載一次。
docker-compose是用來做docker服務編排,參看《Docker從入門到實踐》中的解釋:
Compose 項目目前在 Github 上進行維護,目前最新版本是 1.2.0。Compose 定位是“defining and running complex applications with Docker”,前身是 Fig,兼容 Fig 的模板文件。
Dockerfile 可以讓用戶管理一個單獨的應用容器;而 Compose 則允許用戶在一個模板(YAML 格式)中定義一組相關聯的應用容器(被稱爲一個 project,即項目),例如一個 Web 服務容器再加上後端的數據庫服務容器等。
單個docker用起來確實沒什麼用,docker技術的關鍵在於持續交付,通過與jekins的結合,可以實現這樣的效果:開發人員提交push,然後jekins就自動構建並測試剛提交的代碼,這就是我理解的持續交付。
11、守護進程啓動
使用java命令運行應用非常簡單,但是通常我們都是通過ssh命令連接到服務器並運行它,一旦ssh連接斷開,那麼由它fork的java子進程也就隨之銷燬了。所以我們必須藉助工具將應用作爲服務運行在服務器上:
Systemd
systemd 是Linux 下的一款系統和服務管理器。可以爲Spring Boot應用編寫啓動腳本:
- [Unit]
- Description=Spring Boot Application
- [Service]
- ExecStart=/usr/bin/java -jar location_of_jar_file.jar --spring.config.location=location_of_config.properties --spring.profiles.active=profile
- User=${your expected user}
- [Install]
- WantedBy=multi-user.target
Supervisord
Supervisord配置:
- [program:app]
- command=/usr/bin/java -jar location_of_jar_file.jar --spring.config.location=location_of_config.properties --spring.profiles.active=profile
- user=${your expected user}
- autostart=true
- autorestart=true
- startsecs=10
- startretries=3
12、生產環境運維支持
與開發和測試環境不同的是,當應用部署到生產環境時,需要各種運維相關的功能的支持,包括性能指標、運行信息和應用管理等。所有這些功能都有很多技術和開源庫可以實現。Spring Boot 對這些運維相關的功能進行了整合,形成了一個功能完備和可定製的功能集,稱之爲 Actuator。只需要在 POM 文件中增加對 “org.springframe.boot:spring-boot-starter-actuator” 的依賴就可以添加 Actuator。Actuator 在添加之後,會自動暴露一些 HTTP 服務來提供這些信息。這些 HTTP 服務的說明如表 2。
Spring Boot Actuator 所提供的 HTTP 服務
名稱 | 說明 | 是否包含敏感信息 |
---|---|---|
autoconfig | 顯示 Spring Boot 自動配置的信息。 | 是 |
beans | 顯示應用中包含的 Spring bean 的信息。 | 是 |
configprops | 顯示應用中的配置參數的實際值。 | 是 |
dump | 生成一個 thread dump。 | 是 |
env | 顯示從 ConfigurableEnvironment 得到的環境配置信息。 | 是 |
health | 顯示應用的健康狀態信息。 | 否 |
info | 顯示應用的基本信息。 | 否 |
metrics | 顯示應用的性能指標。 | 是 |
mappings | 顯示 Spring MVC 應用中通過“ @RequestMapping”添加的路徑映射。 | 是 |
shutdown | 關閉應用。 | 是 |
trace | 顯示應用相關的跟蹤(trace)信息。 | 是 |
對於表中的每個服務,通過訪問名稱對應的 URL 就可以獲取到相關的信息。如訪問“/info”就可以獲取到 info 服務對應的信息。服務是否包含敏感信息說明了該服務暴露出來的信息是否包含一些比較敏感的信息,從而確定是否需要添加相應的訪問控制,而不是對所有人都公開。所有的這些服務都是可以配置的,比如通過改變名稱來改變相應的 URL。下面對幾個重要的服務進行介紹。
health 服務
Spring Boot 默認提供了對應用本身、關係數據庫連接、MongoDB、Redis 和 Rabbit MQ 的健康狀態的檢測功能。當應用中添加了 DataSource 類型的 bean 時,Spring Boot 會自動在 health 服務中暴露數據庫連接的信息。應用也可以提供自己的健康狀態信息,如代碼清單 7 所示。
health 服務
@Component public class AppHealthIndicator implements HealthIndicator { @Override public Health health() { return Health.up().build(); } }
應用只需要實現 org.springframework.boot.actuate.health.HealthIndicator 接口,並返回一個 org.springframework.boot.actuate.health.Health 對象,就可以通過 health 服務來獲取所暴露的信息。health 服務返回的結果
{"status":"UP","app":{"status":"UP"},"db":{"status":"UP","database":"HSQL Database Engine","hello":1}}
info 服務
info 服務所暴露的信息是完全由應用來確定的。應用中任何以“info.”開頭的配置參數會被自動的由 info 服務來暴露。只需要往 application.properties 中添加以“info.”開頭的參數即可,如:
info.app_name=My First Spring Boot Application info.app_version=1.0.0
當訪問“/info”時,訪問的 JSON 數據:
{"app_name":"My First Spring Boot Application","app_version":"1.0.0"}
metrics 服務
當訪問 metrics 服務時,可以看到 Spring Boot 通過 SystemPublicMetrics 默認提供的一些系統的性能參數值,包括內存、CPU、Java 類加載和線程等的基本信息。應用可以記錄其他所需要的信息。Spring Boot 默認提供了兩種類型的性能指標記錄方式:gauge 和 counter。gauge 用來記錄單個絕對數值,counter 用來記錄增量或減量值。比如在一個 Web 應用中,可以用 counter 來記錄當前在線的用戶數量。當用戶登錄時,把 counter 的值加 1;當用戶退出時,把 counter 的值減 1。
示例:
@RestController public class GreetingsController { @Autowired private CounterService counterService; @RequestMapping("/greet") public String greet() { counterService.increment("myapp.greet.count"); return "Hello!"; } }
上面代碼添加了對 Spring Boot 提供的 CounterService 的依賴。當 greet 方法被調用時,會把名稱爲“myapp.greet.count”的計數器的值加 1。也就是當用戶每次訪問“/greet”時,該計算器就會被加 1。除了 CounterService 之外,還可以使用 GaugeService 來記錄絕對值