Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目

Spring Boot是什么

Spring基础上再次进行封装,更加简化企业级应用开发。打破Spring的整合,把各种框架的整合进行了封装,封装到starter类库中。

  • 更快的入门
  • 开箱即用:把与具体业务相关的框架集成到一个jar包(starter)里面,starter可以涵盖相关业务开发的所有功能
  • Spring血统:Spring具有的优点,Spring Boot统统都有;Spring不具备的优点,Spring Boot作为其补充
  • 零配置:最大化地减少配置,甚至做到零配置
  • 终极目标:简化开发,抛弃了传统Java EE项目繁琐的配置、学习过程,让企业级应用开发过程更简单

Spring Boot除了可以很好融入Docker之外,其自身就支持嵌入式的TomcatJetty等容器。所以,通过Spring Boot构建的应用不再需要安装Tomcat,将应用打包成war,再部署到Tomcat这样复杂的构建与部署动作,只需将Spring Boot应用打成jar包,并通过java -jar命令直接运行就能启动一个标准化的Web应用,这使得Spring Boot应用变得非常轻便。

我们完全可以通过使用GradleGroovy来开发Spring Boot应用。

Spring Boot与其他框架的关系

Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第1张图片

  • Spring Boot底层基于Spring框架
  • Spring Boot开发web应用时,可以选择性地采用Spring MVCSpring MVC也是基于Spring
  • Spring Cloud是一套分布式的微服务解决方案,里面涵盖的组件(模块)都基于Spring Boot来构建。Spring Cloud是由很多Spring Boot应用组成的

搭建开发环境

  • JDK8+
  • Gradle 4+
  • Eclipse 4.7+(也可选用别的IDE)

Gradle

Gradle官方下载链接:https://gradle.org/releases/

选择想要安装的发布版本,gradle-x.x-bin.zip是需要下载的安装发布版,gradle-x.x-src.zip是源码,gradle-x.x-all.zip则是下载全部的文件。

例如按照下图选择将会下载gradle-4.10.2-bin.zip
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第2张图片
将下载的压缩包在本机的目录下直接解压即可,解压后的目录如下图所示:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第3张图片
接下来为Gradle配置环境变量:

在系统变量中新增一个GRADLE_HOME变量,值为解压后的路径:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第4张图片
接下来还需要修改Path变量,将Gradlebin目录添加进去。在Path变量的最后面添加%GRADLE_HOME%\bin
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第5张图片
配置完成后查看一下本机安装的gradle的版本信息,使用快捷键Win+R弹出的输入框中输入cmd,然后打开命令窗口,在命令窗口中输入gradle -v可以查看到gradle的版本信息,如下图所示即表示配置成功:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第6张图片

Eclipse

打开Eclipse,进入如下设置页面:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第7张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第8张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第9张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第10张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第11张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第12张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第13张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第14张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第15张图片
开发环境搭建完成。

Spring Initializr

Spring Initializr是一个开源的项目,基于这个项目,可以采用配置的形式初始化一个应用。

通过https://start.spring.io可访问Spring Initializr界面,如下图所示:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第16张图片
该界面可提供Spring Boot应用的生成
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第17张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第18张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第19张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第20张图片
会生成如下工程:
在这里插入图片描述
将工程解压,解压后的目录如下图所示:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第21张图片

  • .gitignore:版本管理的忽略文件
  • build.gradlegradle项目的配置文件(核心
  • gradlew:在Linux下的执行脚本(基本不会用到)
  • gradlew.bat:在Windows下的执行脚本(基本不会用到)
//buildscript代码块中脚本优先执行
buildscript {

    //ext用于定义动态属性
	ext {
		springBootVersion = '2.0.0.M4'
	}

    //使用了Maven的中央仓库及Spring自己的仓库(也可以指定其他仓库)
	repositories {
        //中央仓库,因为速度慢,在这里注释掉,改用其他国内镜像仓库
		//mavenCentral()
        //因为本项目使用的是2.0.0.M4版本,不是稳定版本,所以不能保证在镜像仓库中能够找到,所以需要保留Spring自己的仓库
        maven{ url "https://repo.spring.io/snapshot" }
        maven{ url "https://repo.spring.io/milestone" }
        //阿里云镜像仓库
        maven{ url "http://maven.aliyun.com/nexus/content/groups/public/" }
	}

    //依赖关系
	dependencies {
        //classpath声明了在执行其余的脚本时,ClassLoader可以使用这些依赖项
		classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
	}
}

//使用插件
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

//指定了生成的编译文件的版本,默认是打成了jar包
group = 'com.study.spring.cloud'
version = '0.0.1-SNAPSHOT'

//指定编译.java文件的JDK版本
sourceCompatibility = 1.8

//使用了Maven的中央仓库及Spring自己的仓库(也可以指定其他仓库)
repositories {
    //mavenCentral()
    maven{ url "https://repo.spring.io/snapshot" }
    maven{ url "https://repo.spring.io/milestone" }
    maven{ url "http://maven.aliyun.com/nexus/content/groups/public/" }
}

//依赖关系
dependencies {

	//全栈Web开发模块,包含嵌入式Tomcat、Spring MVC
    //该依赖用于编译阶段
	compile('org.springframework.boot:spring-boot-starter-web')

	//通用测试模块,包含JUnit、Hamcrest、Mockito
    //该依赖用于测试阶段
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

对项目进行编译:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第22张图片
显示BUILD SUCCESSFUL即为编译成功

Hello World

  • build.gradle
  • 控制器HelloController
  • 测试用例HelloControllerTest
  • 配置Gradle Wrapper(可选)
  • 运行应用

创建项目

复制前面的initializr-start项目,将副本重命名为hello-world
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第23张图片

将项目导入Eclipse

Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第24张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第25张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第26张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第27张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第28张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第29张图片
导入项目如下:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第30张图片

修改源码

重命名文件:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第31张图片
Application.java一定要处于整个工程的根目录下,这样它才能根据配置去扫描子节点下的SpringBean

修改build.gradle配置:

//指定了生成的编译文件的版本,默认是打成了jar包
group = 'com.study.spring.cloud'
version = '0.0.1-SNAPSHOT'

改为

//指定了生成的编译文件的版本,默认是打成了jar包
group = 'com.study.spring.cloud'
version = '1.0.0'

开发controller

新建一个controller的包:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第32张图片
新建HelloController.java:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第33张图片
代码如下:

package com.study.spring.cloud.weather.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

//用于处理rest请求的controller
@RestController
public class HelloController {

	@RequestMapping("/hello")
	public String hello() {
		return "Hello World!";
	}
	
}

编写测试用例

新建一个controller的包:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第34张图片
新建测试类:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第35张图片
代码如下:

package com.study.spring.cloud.weather.controller;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

//junit的规范
@RunWith(SpringRunner.class)
//Spring Boot的测试
@SpringBootTest
//MVC开发Mock测试
@AutoConfigureMockMvc
public class HelloControllerTest {

	@Autowired
	private MockMvc mockMvc;
	
	@Test
	public void testHello() throws Exception {
		mockMvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON))
		.andExpect(status().isOk())
		.andExpect(content().string(equalTo("Hello World!")));
	}
	
}

运行测试类:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第36张图片

配置文件

Spring Boot的默认配置文件位置为src/main/resources/application.properties。关于Spring Boot应用的配置内容都可以集中在该文件中,根据我们引入的不同Starter模块,可以在这里定义容器端口号、数据库连接信息、日志级别等各种配置信息。比如,我们需要自定义Web模块的服务端口号,可以在application.properties中添加server.port=8888来指定服务端口为8888,也可以通过spring.application.name=hello来指定应用名(该名字在后续Spring Cloud中会被注册为服务名)。

Spring Boot的配置文件除了可以使用传统的properties文件之外,还支持现在被广泛推荐使用的YAML文件。YAML是一个可读性高,用来表达资料序列的格式。由于YAML使用空白符号和分行来分隔资料,使得它特别适合用grep/Python/Perl/Ruby操作。其让人最容易上手的特色是巧妙避开各种封闭符号,如引号、各种括号等,这些符号在巢状结构时会变得复杂而难以辨认。

YAML采用的配置格式不像properties的配置那样以单纯的键值对形式来表示,而是以类似大纲的缩进形式来表示,如下是一段YAML配置信息:

environments:
	dev:
		url:http://dev.bar.com
		name:Developer Setup
	prod:
		url:http://foo.bar.com
		name:My Cool App

与其等价的properties配置如下所示:

environments.dev.url=http://dev.bar.com
environments.dev.name=Developer Setup
environments.prod.url=http://foo.bar.com
environments.prod.name=My Cool App

可以看到YAML配置信息利用阶梯化缩进的方式,其结构更为清晰易读,同时配置内容的字符量也得到显著减少。除此之外,YAML还可以在一个单个文件中通过使用spring.profiles属性来定义多个不同的环境配置。例如下面的内容,在指定为test环境时,server.port将使用8882端口;而在prod环境中,server.port将使用8883端口;如果没有指定环境,server.port将使用8881端口:

server:
	port:8881
---
spring:
	profiles:test
server:
	port:8882
---
spring:
	profiles:prod
server:
	port:8883

YAML目前还无法通过@PropertySource注解来加载配置。但是,YAML将属性加载到内存中保存的时候是有序的,所以当配置文件中的信息需要具备顺序含义时,YAML的配置方式比起properties配置文件更有优势。

自定义参数

除了可以在Spring Boot的配置文件中设置各个Starter模块中预定义的配置属性,也可以在配置文件中定义一些我们需要的自定义属性。比如在application.properties中添加:

book.name=SpringCloudInAction
book.author=Xxx

然后,在应用中可以通过@Value注解来加载这些自定义的参数,比如:

@Component
public class Book{
	
	@Value("${book.name}")
	private String name;

	@Value("${book.author}")
	private String author;

	//省略getter和setter
}

@Value注解加载属性值的时候可以支持两种表达式来进行配置:

  • 一种是上面介绍的PlaceHolder方式,格式为${...},大括号内为PlaceHolder
  • 另一种是使用SpEL表达式(Spring Expression Language),格式为#{...},大括号内为SpEL表达式

参数引用

application.properties中的各个参数之间可以直接通过使用PlaceHolder的方式来进行引用,就像下面的设置:

book.name=SpringCloud
book.author=Xxx
book.desc=${book.author} is writing 《${book.name}》

book.desc参数引用了上文中定义的book.namebook.author属性,最后该属性的值就是Xxx is writing 《SpringCloud》

使用随机数

在一些特殊情况下,我们希望有些参数每次被加载的时候不是一个固定的值,比如密钥、服务端口等。在Spring Boot的属性配置文件中,可以通过使用${random}配置来产生随机的int值、long值或者string字符串,这样我们就可以容易地通过配置随机生成属性,而不是在程序中通过编码来实现这些逻辑。${random}的配置方式主要有以下几种:

#随机字符串
com.didispace.blog.value=${random.value}

#随机int
com.didispace.blog.number=${random.int}

#随机long
com.didispace.blog.bignumber=${random.long}

#10以内的随机数
com.didispace.blog.test1=${random.int(10)}

#10~20的随机数
com.didispace.blog.test2=${random.int[10,20]}

该配置方式可以设置应用端口等场景,以避免在本地调试时出现端口冲突的麻烦。

命令行参数

在用命令行方式启动Spring Boot应用时,连续的两个减号--就是对application.properties中的属性值进行赋值的标识。所以,java -jar xxx.jar --server.port=8888命令,等价于在application.properties中添加属性server.port=8888

多环境配置

对于多环境的配置,各种项目构建工具或是框架的基本思路是一致的,通过配置多份不同环境的配置文件,再通过打包命令指定需要打包的内容之后进行区分打包,Spring Boot也不例外,或者说实现起来更加简单。

Spring Boot中,多环境配置的文件名需要满足application-{profile}.properties的格式,其中{profile}对应你的环境标识,如下所示:

  • application-dev.properties:开发环境
  • application-test.properties:测试环境
  • application-prod.properties:生产环境

至于具体哪个配置文件会被加载,需要在application.properties文件中通过spring.profiles.active属性来设置,其值对应配置文件中的{profile}值。如spring.profiles.active=test就会加载application-test.properties配置文件内容。

多环境的配置思路:

  • application.properties中配置通用内容,并设置spring.profiles.active=dev,以开发环境为默认配置。
  • application-{profile}.properties中配置各个环境不同的内容。
  • 通过命令行方式去激活不同环境的配置。

加载顺序

为了能够更合理地重写各属性的值,Spring Boot使用了下面这种较为特别的属性加载顺序:

  1. 在命令行中传入的参数
  2. SPRING_APPLICATION_JSON中的属性。SPRING_APPLICATION_JSON是以JSON格式配置在系统环境变量中的内容
  3. java:comp/env中的JNDI属性
  4. Java的系统属性,可以通过System.getProperties()获得的内容
  5. 操作系统的环境变量
  6. 通过random.*配置的随机属性
  7. 位于当前应用jar包之外,针对不同{profile}环境的配置文件内容,例如application-{profile}.properties或是YAML定义的配置文件
  8. 位于当前应用jar包之内,针对不同{profile}环境的配置文件内容,例如application-{profile}.properties或是YAML定义的配置文件
  9. 位于当前应用jar包之外的application.propertiesYAML配置内容
  10. 位于当前应用jar包之内的application.propertiesYAML配置内容
  11. @Configuration注解修改的类中,通过@PropertySource注解定义的属性
  12. 应用默认属性,使用SpringApplication.setDefaultProperties定义的内容

优先级按照上面的顺序由高到低,数字越小优先级越高。

可以看到,其中第7项和第9项都是从应用jar包之外读取配置文件,所以,实现外部化配置的原理就是从此切入,为其指定外部配置文件的加载位置来取代jar包之内的配置内容。通过这样的实现,我们的工程在配置中就变得非常干净,只需在本地放置开发需要的配置即可,而不用关心其他环境的配置,由其对应环境的负责人去维护即可。

监控与管理

在微服务架构中,我们将原本庞大的单体系统拆分成多个提供不同服务的应用。虽然各个应用的内部逻辑因分解而得以简化,但是由于部署应用的数量成倍增长,使得系统的维护复杂度大大提升。为了能对这些成倍增长的应用做到高效运维,传统的运维方式显然是不合适的,所以我们需要实现一套自动化的监控运维机制,而这套机制的运行基础就是不间断地收集各个微服务应用的各项指标情况,并根据这些基础指标信息来制定监控和预警规则,更进一步甚至做到一些自动化的运维操作等。

为了让运维系统能够获取各个微服务应用的相关指标以及实现一些常规操作控制,我们需要开发一套专门用于植入各个微服务应用的接口供监控系统采集信息。而这些接口往往有很大一部分指标都是类似的,比如环境变量、垃圾收集信息、内存信息、线程池信息等。

当我们决定用Spring Boot来作为微服务框架时,除了它强大的快速开发功能之外,还因为它在Starter POMs中提供了一个特殊依赖模块spring-boot-starter-actuator,引入该模块能够自动为Spring Boot构建的应用提供一系列用于监控的端点。同时,Spring Cloud在实现各个微服务组件的时候,进一步为该模块做了不少扩展,比如,为原生端点增加了更多的指标和度量信息(比如在整合Eureka的时候会为/health端点增加相关的信息),并且根据不同的组件还提供了更多有空的端点(比如,为API网关组件Zuul提供了/routes端点来返回路由信息)。

spring-boot-starter-actuator模块的实现对于实施微服务的中小团队来说,可以有效地省去或大大减少监控系统在采集应用指标时的开发量。当然,它也并不是万能的,有时候也需要对其做一些简单的扩展来帮助我们实现自身系统个性化的监控需求。

初识actuator

在现有的Spring Boot应用中引入该模块非常简单,只需要在pom.xmldependency节点中,新增spring-boot-starter-actuator的依赖即可,具体如下:

<dependency>
	<groupId>org.springframework.bootgroupId>
	<artifactId>spring-boot-starter-actuatorartifactId>
dependency>

增加该依赖之后,重新启动应用,可以在控制台的输出中看到一批端点定义,这些端点并非我们自己在程序中创建的,而是由spring-boot-starter-actuator模块根据应用依赖和配置自动创建出来的监管和管理端点。通过这些端点,我们可以实时获取应用的各项监控指标,比如访问/health端点,我们可以获得如下信息:

{
	"status":"UP",
	"diskSpace":{
		"status":"UP",
		"total":491270434816,
		"free":383870214144,
		"threshold":10485760
	}
}

在没有引入其他依赖之前,该端点的内容较为简单,后续我们在使用Spring Cloud的各个组件之后,它的返回会变得非常丰富,这些内容将帮助我们制定更为个性化的监控策略。

原生端点

根据端点的作用,可以将原生端点分为以下三大类:

  • 应用配置类:获取应用程序中加载的应用配置、环境变量、自动化配置报告等与Spring Boot应用密切相关的配置类信息。
  • 度量指标类:获取应用程序运行过程中用于监控的度量指标,比如内存信息、线程池信息、HTTP请求统计等。
  • 操作控制类:提供了对应用的关闭等操作类功能。

应用配置类

由于Spring Boot为了改善传统Spring应用繁杂的配置内容,采用了包扫描和自动化配置的机制来加载原本集中于xml文件中的各项内容。虽然这样的做法,让我们的代码变得非常简洁,但是整个应用的实例创建和依赖关系等信息都被离散到了各个配置类的注解上,这使得我们分析整个应用中资源和实例的各种关系变得非常的困难。而这类端点就可以帮助我们轻松的获取一系列关于Spring 应用配置内容的详细报告,比如:自动化配置的报告、Bean创建的报告、环境属性的报告等。

/autoconfig

/autoconfig:该端点用来获取应用的自动化配置报告,其中包括所有自动化配置的候选项。同时还列出了每个候选项自动化配置的各个先决条件是否满足。所以,该端点可以帮助我们方便的找到一些自动化配置为什么没有生效的具体原因。该报告内容将自动化配置内容分为两部分:

  • positiveMatches中返回的是条件匹配成功的自动化配置
  • negativeMatches中返回的是条件匹配不成功的自动化配置
{
    "positiveMatches": { // 条件匹配成功的
        "EndpointWebMvcAutoConfiguration": [
            {
                "condition": "OnClassCondition",
                "message": "@ConditionalOnClass classes found: javax.servlet.Servlet,org.springframework.web.servlet.DispatcherServlet"
            },
            {
                "condition": "OnWebApplicationCondition",
                "message": "found web application StandardServletEnvironment"
            }
        ],
        ...
    },
    "negativeMatches": {  // 条件不匹配成功的
        "HealthIndicatorAutoConfiguration.DataSourcesHealthIndicatorConfiguration": [
            {
                "condition": "OnClassCondition",
                "message": "required @ConditionalOnClass classes not found: org.springframework.jdbc.core.JdbcTemplate"
            }
        ],
        ...
    }
}

从如上示例中我们可以看到,每个自动化配置候选项中都有一系列的条件,比如上面没有成功匹配的HealthIndicatorAutoConfiguration.DataSourcesHealthIndicatorConfiguration配置,它的先决条件就是需要在工程中包含org.springframework.jdbc.core.JdbcTemplate类,由于我们没有引入相关的依赖,它就不会执行自动化配置内容。所以,当我们发现有一些期望的配置没有生效时,就可以通过该端点来查看没有生效的具体原因。

/beans

/beans:该端点用来获取应用上下文中创建的所有Bean

[
    {
        "context": "hello:dev:8881",
        "parent": null,
        "beans": [
            {
                "bean": "org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DispatcherServletConfiguration",
                "scope": "singleton",
                "type": "org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DispatcherServletConfiguration$$EnhancerBySpringCGLIB$$3440282b",
                "resource": "null",
                "dependencies": [
                    "serverProperties",
                    "spring.mvc.CONFIGURATION_PROPERTIES",
                    "multipartConfigElement"
                ]
            },
            {
                "bean": "dispatcherServlet",
                "scope": "singleton",
                "type": "org.springframework.web.servlet.DispatcherServlet",
                "resource": "class path resource [org/springframework/boot/autoconfigure/web/DispatcherServletAutoConfiguration$DispatcherServletConfiguration.class]",
                "dependencies": []
            }
        ]
    }
]

如上示例中,我们可以看到在每个bean中都包含了下面这几个信息:

  • beanBean的名称
  • scopeBean的作用域
  • typeBeanJava类型
  • reourceclass文件的具体路径
  • dependencies:依赖的Bean名称

/configprops

/configprops:该端点用来获取应用中配置的属性信息报告。从下面该端点返回示例的片段中,我们看到返回了关于该短信的配置信息,prefix属性代表了属性的配置前缀,properties代表了各个属性的名称和值。所以,我们可以通过该报告来看到各个属性的配置路径,比如我们要关闭该端点,就可以通过使用endpoints.configprops.enabled=false来完成设置。

{
    "configurationPropertiesReportEndpoint": {
        "prefix": "endpoints.configprops",
        "properties": {
            "id": "configprops",
            "sensitive": true,
            "enabled": true
        }
    },
    ...
}

/env

/env:该端点与/configprops不同,它用来获取应用所有可用的环境属性报告。包括:环境变量、JVM属性、应用的配置配置、命令行中的参数。从下面该端点返回的示例片段中,我们可以看到它不仅返回了应用的配置属性,还返回了系统属性、环境变量等丰富的配置信息,其中也包括了应用还没有没有使用的配置。所以它可以帮助我们方便地看到当前应用可以加载的配置信息,并配合@ConfigurationProperties注解将它们引入到我们的应用程序中来进行使用。另外,为了配置属性的安全,对于一些类似密码等敏感信息,该端点都会进行隐私保护,但是我们需要让属性名中包含:passwordsecretkey这些关键词,这样该端点在返回它们的时候会使用*来替代实际的属性值。

{
    "profiles": [
        "dev"
    ],
    "server.ports": {
        "local.server.port": 8881
    },
    "servletContextInitParams": {
        
    },
    "systemProperties": {
        "idea.version": "2016.1.3",
        "java.runtime.name": "Java(TM) SE Runtime Environment",
        "sun.boot.library.path": "C:\\Program Files\\Java\\jdk1.8.0_91\\jre\\bin",
        "java.vm.version": "25.91-b15",
        "java.vm.vendor": "Oracle Corporation",
        ...
    },
    "systemEnvironment": {
        "configsetroot": "C:\\WINDOWS\\ConfigSetRoot",
        "RABBITMQ_BASE": "E:\\tools\\rabbitmq",
        ...
    },
    "applicationConfig: [classpath:/application-dev.properties]": {
        "server.port": "8881"
    },
    "applicationConfig: [classpath:/application.properties]": {
        "server.port": "8885",
        "spring.profiles.active": "dev",
        "info.app.name": "spring-boot-hello",
        "info.app.version": "v1.0.0",
        "spring.application.name": "hello"
    }
}

/mappings

/mappings:该端点用来返回所有Spring MVC的控制器映射关系报告。从下面的示例片段中,我们可以看该报告的信息与我们在启用Spring MVCWeb应用时输出的日志信息类似,其中bean属性标识了该映射关系的请求处理器,method属性标识了该映射关系的具体处理类和处理函数。

{
    "/webjars/**": {
        "bean": "resourceHandlerMapping"
    },
    "/**": {
        "bean": "resourceHandlerMapping"
    },
    "/**/favicon.ico": {
        "bean": "faviconHandlerMapping"
    },
    "{[/hello]}": {
        "bean": "requestMappingHandlerMapping",
        "method": "public java.lang.String com.didispace.web.HelloController.index()"
    },
    "{[/mappings || /mappings.json],methods=[GET],produces=[application/json]}": {
        "bean": "endpointHandlerMapping",
        "method": "public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()"
    },
    ...
}

/info

/info:该端点用来返回一些应用自定义的信息。默认情况下,该端点只会返回一个空的json内容。我们可以在application.properties配置文件中通过info前缀来设置一些属性,比如下面这样:

info.app.name=spring-boot-hello
info.app.version=v1.0.0

再访问/info端点,我们可以得到下面的返回报告,其中就包含了上面我们在应用自定义的两个参数。

{
    "app": {
        "name": "spring-boot-hello",
        "version": "v1.0.0"
    }
}

度量指标类

上面我们所介绍的应用配置类端点所提供的信息报告在应用启动的时候都已经基本确定了其返回内容,可以说是一个静态报告。而度量指标类端点提供的报告内容则是动态变化的,这些端点提供了应用程序在运行过程中的一些快照信息,比如:内存使用情况、HTTP请求统计、外部资源指标等。这些端点对于我们构建微服务架构中的监控系统非常有帮助,由于Spring Boot应用自身实现了这些端点,所以我们可以很方便地利用它们来收集我们想要的信息,以制定出各种自动化策略。下面,我们就来分别看看这些强大的端点功能。

/metrics

/metrics:该端点用来返回当前应用的各类重要度量指标,比如:内存信息、线程信息、垃圾回收信息等。

{
  "mem": 541305,
  "mem.free": 317864,
  "processors": 8,
  "instance.uptime": 33376471,
  "uptime": 33385352,
  "systemload.average": -1,
  "heap.committed": 476672,
  "heap.init": 262144,
  "heap.used": 158807,
  "heap": 3701248,
  "nonheap.committed": 65856,
  "nonheap.init": 2496,
  "nonheap.used": 64633,
  "nonheap": 0,
  "threads.peak": 22,
  "threads.daemon": 20,
  "threads.totalStarted": 26,
  "threads": 22,
  "classes": 7669,
  "classes.loaded": 7669,
  "classes.unloaded": 0,
  "gc.ps_scavenge.count": 7,
  "gc.ps_scavenge.time": 118,
  "gc.ps_marksweep.count": 2,
  "gc.ps_marksweep.time": 234,
  "httpsessions.max": -1,
  "httpsessions.active": 0,
  "gauge.response.beans": 55,
  "gauge.response.env": 10,
  "gauge.response.hello": 5,
  "gauge.response.metrics": 4,
  "gauge.response.configprops": 153,
  "gauge.response.star-star": 5,
  "counter.status.200.beans": 1,
  "counter.status.200.metrics": 3,
  "counter.status.200.configprops": 1,
  "counter.status.404.star-star": 2,
  "counter.status.200.hello": 11,
  "counter.status.200.env": 1
}

从上面的示例中,我们看到有这些重要的度量值:

  • 系统信息:包括处理器数量processors、运行时间uptimeinstance.uptime、系统平均负载systemload.average
  • mem.*:内存概要信息,包括分配给应用的总内存数量以及当前空闲的内存数量。这些信息来自java.lang.Runtime
  • heap.*:堆内存使用情况。这些信息来自java.lang.management.MemoryMXBean接口中getHeapMemoryUsage方法获取的java.lang.management.MemoryUsage
  • nonheap.*:非堆内存使用情况。这些信息来自java.lang.management.MemoryMXBean接口中getNonHeapMemoryUsage方法获取的java.lang.management.MemoryUsage
  • threads.*:线程使用情况,包括线程数、守护线程数(daemon)、线程峰值(peak)等,这些数据均来自java.lang.management.ThreadMXBean
  • classes.*:应用加载和卸载的类统计。这些数据均来自java.lang.management.ClassLoadingMXBean
  • gc.*:垃圾收集器的详细信息,包括垃圾回收次数gc.ps_scavenge.count、垃圾回收消耗时间gc.ps_scavenge.time、标记-清除算法的次数gc.ps_marksweep.count、标记-清除算法的消耗时间gc.ps_marksweep.time。这些数据均来自java.lang.management.GarbageCollectorMXBean
  • httpsessions.*Tomcat容器的会话使用情况。包括最大会话数httpsessions.max和活跃会话数httpsessions.active。该度量指标信息仅在引入了嵌入式Tomcat作为应用容器的时候才会提供。
  • gauge.*HTTP请求的性能指标之一,它主要用来反映一个绝对数值。比如上面示例中的gauge.response.hello: 5,它表示上一次hello请求的延迟时间为5毫秒。
  • counter.*HTTP请求的性能指标之一,它主要作为计数器来使用,记录了增加量和减少量。如上示例中counter.status.200.hello: 11,它代表了hello请求返回200状态的次数为11

对于gauge.*counter.*的统计,这里有一个特殊的内容请求star-star,它代表了对静态资源的访问。这两类度量指标非常有用,我们不仅可以使用它默认的统计指标,还可以在程序中轻松的增加自定义统计值。只需要通过注入org.springframework.boot.actuate.metrics.CounterServiceorg.springframework.boot.actuate.metrics.GaugeService来实现自定义的统计指标信息。比如:我们可以像下面这样自定义实现对hello接口的访问次数统计:

@RestController
public class HelloController {
    
    @Autowired
    private CounterService counterService;

    @RequestMapping("/hello")
    public String greet() {
        counterService.increment("didispace.hello.count");
        return "";
    }
  
}

/metrics端点可以提供应用运行状态的完整度量指标报告,这项功能非常的实用,但是对于监控系统中的各项监控功能,它们的监控内容、数据收集频率都有所不同,如果我们每次都通过全量获取报告的方式来收集,略显粗暴。所以,我们还可以通过/metrics/{name}接口来更细粒度的获取度量信息,比如我们可以通过访问/metrics/mem.free来获取当前可用内存数量。

/health

/health:该端点在一开始的示例中我们已经使用过了,它用来获取应用的各类健康指标信息。在spring-boot-starter-actuator模块中自带实现了一些常用资源的健康指标检测器。这些检测器都通过HealthIndicator接口实现,并且会根据依赖关系的引入实现自动化装配,比如下面列出的这些:

检测器 功能
DiskSpaceHealthIndicator 低磁盘空间检测
DataSourceHealthIndicator 检测DataSource的连接是否可用
MongoHealthIndicator 检测Mongo数据库是否可用
RabbitHealthIndicator 检测Rabbit服务器是否可用
RedisHealthIndicator 检测Redis服务器是否可用
SolrHealthIndicator 检测Solr服务器是否可用

有时候,我们可能还会用到一些Spring BootStarter POMs中还没有封装的产品来进行开发,比如:当使用RocketMQ作为消息代理时,由于没有自动化配置的检测器,所以我们需要自己来实现一个用来采集健康信息的检测器。比如,我们可以在Spring Boot的应用中,为org.springframework.boot.actuate.health.HealthIndicator接口实现一个对RocketMQ的检测器类:

@Component
public class RocketMQHealthIndicator implements HealthIndicator {

    @Override
    public Health health() {
        int errorCode = check();
        if (errorCode != 0) {
          return Health.down().withDetail("Error Code", errorCode).build();
        }
        return Health.up().build();
    }

  	private int check() {
     	// 对监控对象的检测操作
  	}
}

通过重写health()函数来实现健康检查,返回的Heath对象中,共有两项内容,一个是状态信息,除了该示例中的UPDOWN之外,还有UNKNOWNOUT_OF_SERVICE,可以根据需要来实现返回;还有一个详细信息,采用Map的方式存储,在这里通过withDetail函数,注入了一个Error Code信息,我们也可以填入一下其他信息,比如,检测对象的IP地址、端口等。重新启动应用,并访问/health接口,我们在返回的JSON字符串中,将会包含了如下信息:

"rocketMQ": {
  "status": "UP"
}

/dump

/dump:该端点用来暴露程序运行中的线程信息。它使用java.lang.management.ThreadMXBean的dumpAllThreads方法来返回所有含有同步信息的活动线程详情。

/trace

/trace:该端点用来返回基本的HTTP跟踪信息。默认情况下,跟踪信息的存储采用org.springframework.boot.actuate.trace.InMemoryTraceRepository实现的内存方式,始终保留最近的100条请求记录。它记录的内容格式如下:

[
    {
        "timestamp": 1482570022463,
        "info": {
            "method": "GET",
            "path": "/metrics/mem",
            "headers": {
                "request": {
                    "host": "localhost:8881",
                    "connection": "keep-alive",
                    "cache-control": "no-cache",
                    "user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36",
                    "postman-token": "9817ea4d-ad9d-b2fc-7685-9dff1a1bc193",
                    "accept": "*/*",
                    "accept-encoding": "gzip, deflate, sdch",
                    "accept-language": "zh-CN,zh;q=0.8"
                },
                "response": {
                    "X-Application-Context": "hello:dev:8881",
                    "Content-Type": "application/json;charset=UTF-8",
                    "Transfer-Encoding": "chunked",
                    "Date": "Sat, 24 Dec 2016 09:00:22 GMT",
                    "status": "200"
                }
            }
        }
    },
    ...
]

操作控制类

实际上,由于之前介绍的所有端点都是用来反映应用自身的属性或是运行中的状态,相对于操作控制类端点没有那么敏感,所以他们默认都是启用的。而操作控制类端点拥有更强大的控制能力,如果要使用它们的话,需要通过属性来配置开启。

在原生端点中,只提供了一个用来关闭应用的端点:/shutdown。我们可以通过如下配置开启它:

endpoints.shutdown.enabled=true

在配置了上述属性之后,只需要访问该应用的/shutdown端点就能实现关闭该应用的远程操作。由于开放关闭应用的操作本身是一件非常危险的事,所以真正在线上使用的时候,我们需要对其加入一定的保护机制,比如:定制Actuator的端点路径、整合Spring Security进行安全校验等。

Spring Boot的三种运行方式

java -jar xxx.jar

在命令行中编译项目:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第37张图片
在这里插入图片描述
进入项目中buildlibs目录,可以看到应用的jar包:
在这里插入图片描述
通过命令行运行jar包:
在这里插入图片描述
运行结果如下:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第38张图片
访问http://localhost:8080/hello页面:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第39张图片
在命令行使用快捷键Ctrl+C可将应用停止运行。

gradle bootRun

通过命令行运行:
在这里插入图片描述

IDE里面右键项目

Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第40张图片
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第41张图片
访问http://localhost:8080/hello页面:
Spring Cloud学习笔记1——Spring Boot 简介、环境搭建、入门项目_第42张图片

你可能感兴趣的:(Spring,Cloud)