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
如果你要选择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包管理、以及打包部署变的非常方便。
2、Maven构建Spring Boot框架的可执行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>
1.4改变Java版本
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
target/myproject-1.0.0.jartarget/myproject-1.0.0.jar.original
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>
1、groupId和artifactId以及version都是可以随便填写的 ,scope必须填写为system,而systemPath我们现在我们jar包的目录地址就可以了
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());
- }
- }
修改pom文件中jar 为 war
- <!-- <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
restart
- #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 duqi@example.com
#将打包好的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 来记录绝对值。