文章目录
- 1.题目问答
- 2.配置详情
- 2.1配置文件
- 2.2多环境配置
- 2.3自定义参数
- 2.4命令行参数
- 2.5加载顺序
- 3.Starter POMs
- 4.监控与管理—actuator
- 4.1. 应用配置类
- 4.1.1./autoconfg
- 4.1.2. /beans
- 4.1.3. /configprops
- 4.1.4 /env
- 4.1.5./mappings
- 4.1.6./info
- 4.2. 度量指标类
- 4.2.1. /metrics
- 4.2.2. /health
- 4.2.3./dump
- 4.2.3./trace
- 4.3 操作控制类
1.题目问答
Spring Boot的宗旨是希望通过设计大量的自动化配置等方式来简化 Spring 原有样板化的配置,使得开发者可以快速构建应用。除了解决配置问题之外,Spring Boot 对于构建、部署等做了优化,Spring Boot还通过一系列Starter POMs的定义,让我们整合各项功能的时候,不需要在Maven的pom.xml中维护那些错综复杂的依赖关系,而是通过类似模块化的 Starter 模块定义来引用,使得依赖管理工作变得更为简单。
在如今容器化大行其道的时代,Spring Boot除了可以很好融入Docker之外,其自身就支持嵌入式的 Tomcat、Jetty 等容器。所以,通过 Spring Boot 构建的应用不再需要安装Tomcat,将应用打包成war,再部署到 Tomcat 这样复杂的构建与部署动作,只需将 SpringBoot 应用打成jar 包,并通过 java -jar 命令直接运行就能启动一个标准化的 Web 应用,这使得 Spring Boot 应用变得非常轻便。
1.启动 Spring Boot 应用的方式:
- 作为一个 Java 应用程序,可以直接通过运行拥有 main 函数的类来启动。
- 在 Maven 配置中,之前提到了 spring-boot插件,可以使用它来启动,比如执行 mvn spring-boot:run命令,或是直接单击IDE中对 Maven 插件的工具,例如Intelli]中的支持:
- 在服务器上部署运行时,通常先使用mvn insta11将应用打包成jar 包,再通过
java -jar xxx.jar 来启动应用。
2.配置详情
2.1配置文件
src/main/resources目录是Spring Boot 的配置目录,默认的配置文件位置为src/main/resources/application.properties。关于 Spring Boot 应用的配置内容都可以集中在该文件中,比如定义容器端口号、数据库连接信息、日志级别等各种配置信息。
Spring Boot 的配置文件除了可以使用传统的properties文件之外,还支持现在被广泛推荐使用的 YAML 文件。YAML可以通过使用 spring.profiles属性来定义多个不同的环境配置。
注意 YAML目前还有一些不足,它无法通过@PropertySource 注解来加载配置。但是,YAML 将属性加载到内存中保存的时候是有序的,所以当配置文件中的信息需要具备顺序含义时,YAML的配置方式比起 properties 配置文件更有优势。
2.2多环境配置
对于多环境的配置,在 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 配置文件内容。
2.3自定义参数
可以在配置文件 application.properties中定义一些我们需要的自定义属性。然后,在应用中可以通过@Value 注解来加载这些自定义的参数。
@Value 注解加载属性值的时候可以支持两种表达式来进行配置,如下所示
- 一种是上面介绍的 PlaceHolder 方式,格式为${…},大括号内为 PlaceHolder。
- 另一种是使用 SpEL表达式(SpringExpressionLanguage),格式为#{…},大括号内为 SpEL 表达式。
**参数引用:**在 application.properties中的各个参数之间可以直接通过使用PlaceHolder 的方式来进行引用。
使用随机数:在 Spring Boot 的属性配置文件中,可以通过使用${random}配置来产生随机的 int 值、long 值或者 string 字符串,这样我们就可以容易地通过配置随机生成属性,而不是在程序中通过编码来实现这些逻辑。
${random}的配置方式主要有以下几种,读者可作为参考使用。
com.didispace.blog.value=${random.value}#随机字符串
com.didispace.blog.number=${random.int}#随机 int
com.didispace.blog.bignumber=${random.long }#随机 long
com.didispace.blog.test1=${random.int(10)}# 10 以内的随机数
com.didispace.blog.test2=${random.int[10,20]}# 10~20的随机数
2.4命令行参数
可以在命令行中指定应用的参数,比如java-jarxxx.jar–server.port=8888,连续的两个减号–就是对application.properties中的属性值进行赋值的标识。
2.5加载顺序
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.properties 和 YAML 配置内容
10.位于当前应用jar 包之内的 application.properties 和 YAML 配置内容。
11.在@Configuration 注解修改的类中,通过@PropertySource 注解定义的属性。
12.应用默认属性,使用 SpringApplication.setDefaultProperties 定义的内容。
优先级按上面的顺序由高到低,数字越小优先级越高。
可以看到,其中第7项和第9项都是从应用iar包之外读取配置文件,所以,实现外部化配置的原理就是从此切入,为其指定外部配置文件的加载位置来取代jar 包之内的配置内容。通过这样的实现,我们的工程在配置中就变得非常干净,只需在本地放置开发需要的配置即可,而不用关心其他环境的配置,由其对应环境的负责人去维护即可。
3.Starter POMs
Spring Boot 的 Starter POMs采用 spring-boot-starter-*的命名方式,*代表一个特别的应用功能模块,比如web、test。
4.监控与管理—actuator
监控系统采集信息有很大一部分指标都是类似的,比如环境变量、垃圾收集信息、内存信息、线程池信息等。
Spring Boot在 Starter POMs 中提供了一个特殊依赖模块 spring-boot-starter-actuator。引入该模块能够自动为 Spring Boot 构建的应用提供一系列用于监控的端点。包括原生提供的端点以及一些常用的扩展和配置方式等。
在pom.xml中添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
根据端点的作用,原生端点分为以下三类:
- 应用配置类:获取应用程序中加载的应用配置、环境变量、自动化配置报告等与Spring Boot 应用密切相关的配置类信息。
- 度量指标类:获取应用程序运行过程中用于监控的度量指标,比如内存信息、线程池信息、HTTP请求统计等。
- 操作控制类:提供了对应用的关闭等操作类功能。
4.1. 应用配置类
由于 Spring Boot 为了改善传统 Spring 应用繁杂的配置内容,采用了包扫描和自动化配置的机制来加载原本集中于XML文件中的各项内容。虽然这样的做法让我们的代码变得非常简洁,但是整个应用的实例创建和依赖关系等信息都被离散到了各个配置类的注解上,这使我们分析整个应用中资源和实例的各种关系变得非常困难。而这类端点可以帮助我们轻松获取一系列关于 Spring 应用配置内容的详细报告,比如自动化配置的报告、Bean 创建的报告、环境属性的报告等。
4.1.1./autoconfg
/autoconfg:该端点用来获取应用的自动化配置报告,其中包括所有自动化配置的候选项。同时还列出了每个候选项是否满足自动化配置的各个先决条件。所以,该端点可以帮助我们方便地找到一些自动化配置为什么没有生效的具体原因。该报告内容将自动化配置内容分为以下两部分。
- positiveMatches中返回的是条件匹配成功的自动化配置。
- negativeMatches中返回的是条件匹配不成功的自动化配置。
4.1.2. /beans
/beans:该端点用来获取应用上下文中创建的所有Bean。
在每个Bean中都包含了下面这些信息
- bean:Bean的名称。
- scope:Bean的作用域。
- type:Bean的Java类型
- resource:class文件的具体路径
- dependencies:依赖的Bean 名称。
4.1.3. /configprops
/configprops:该端点用来获取应用中配置的属性信息报告。prefix属性代表了属性的配置前缀,properties代表了各个属性的名称和值。可以通过该报告来看到各个属性的配置路径,可以通过使用endpoints.configprops.enabled=false来关闭该端点。
4.1.4 /env
**/env:**该端点与/confgprops不同,它用来获取应用所有可用的环境属性报告。包括环境变量、JVM 属性、应用的配置属性、命令行中的参数。它可以帮助我们方便地看到当前应用可以加载的配置信息,并配合@ConfigurationProperties注解将它们引入到我们的应用程序中来进行使用。另外,为了配置属性的安全,对于一些类似密码等敏感信息,该端点都会进行隐私保护,但是我们需要让属性名中包含 password、secret、key 这些关键词,这样该端点在返回它们的时候会使用*来替代实际的属性值。
4.1.5./mappings
**/mappings:**该端点用来返回所有 Spring MVC的控制器映射关系报告。bean属性标识了该映射关系的请求处理器,method属性标识了该映射关系的具体处理类和处理函数。
4.1.6./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"
}
}
4.2. 度量指标类
应用配置类端点所提供的信息报告在应用启动的时候就已经基本确定了其返回内容,可以说是一个静态报告。而度量指标类端点提供的报告内容则是动态变化的,这些端点提供了应用程序在运行过程中的一些快照信息,比如内存使用情况、HTTP请求统计、外部资源指标等。这些端点对于我们构建微服务架构中的监控系统非常有帮助。
4.2.1. /metrics
/metrics:该端点用来返回当前应用的各类重要度量指标,比如内存信息、线程信息垃圾回收信息等。包含以下度量值:
- 系统信息:包括处理器数量processors、运行时间uptime和instance.uptime、系统平均负载systemload.average。
- mem.*:内存概要信息,包括分配给应用的总内存数量以及当前空闲的内存数量。这些信息来自java.lang.Runtime。
- heap.*:堆内存使用情况。这些信息来自java.lang.management.MemoryMXBean 接口中getHeapMemoryUsage 方法获取的 java.lang.management.MemoryUsage.
- nonheap.*:非堆内存使用情况。这些信息来自java.lang.managementMemoryMXBean接口中getNonHeapMemoryUsage方法获取的java.lang.management.MemoryUsage.
- threads.*:线程使用情况,包括线程数、守护线程数(daemon)、线程峰值(peak)等,这些数据均来自java.lang.management.ThreadMXBean。
- classes.*:应用加载和卸载的类统计。这些数据均来自java.lang.management.ClassLoadinqMxBean。
- gc.*:垃圾收集器的详细信息,包括垃圾回收次数gc.ps scavenge.count、垃圾回收消耗时间 gc.ps scavenge.time、标记-清除算法的次数 gc.psmarksweep.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,它代表了 he1lo请求返回 200状态的次数为11。
对于 gauge.*和counter.*的统计,这里有一个特殊的内容请求star-star,它代表了对静态资源的访问。这两类度量指标非常有用,我们不仅可以使用它默认的统计指标,还可以在程序中轻松地增加自定义统计值。只需要通过注入org.springframework.boot.actuate.metrics.CounterService 和 orgspringframework.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来获取当前可用内存数量。
4.2.2. /health
/health:用来获取应用的各类健康指标信息。在 spring-boot-starter-actuator 模块中自带实现了一些常用资源的健康指标检测器。这些检测器都通过 HealthIndicator接口实现,并且会根据依赖关系的引入实现自动化装配,比如下面列出的这些。
检测器 | 功能 |
---|---|
DiskSpaceHealthIndicator | 低磁盘空间检测 |
DataSourceHealthIndicator | 检测 DataSource 的连接是否可用 |
MongoHealthIndicator | 检测 Mongo 数据库是否可用 |
RabbitHealthIndicator | 检测 Rabbit 服务器是否可用 |
RedisHealthIndicator | 检测 Redis 服务器是否可用 |
SolrHealthIndicator | 检测 Solr 服务器是否可用 |
有时候,我们可能还会用到一些 Spring Boot的 Starter 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 对象中,共有两项内容,一个是状态信息,除了该示例中的UP与DOWN之外,还有UNKNOWN和OUT_OF_SERVICE,可以根据需要来实现返回;还有一个详细信息,采用Map的方式存储,在这里通过withDetail函数,注入了一个Error Code 信息,我们也可以填入其他信息,比如,检测对象的IP地址、端口等。重新启动应用,并访问/health接口,我们在返回的JSON字符串中,将会包含如下信息:
"rocketMQ" :{"status": "UP"}
4.2.3./dump
/dump:该端点用来暴露程序运行中的线程信息。它使用java.lang.management
ThreadMxBean的dumpAllThreads方法来返回所有含有同步信息的活动线程详情。
4.2.3./trace
**/trace:**该端点用来返回基本的HTTP 跟踪信息。默认情况下,跟踪信息的存储采用org.springframework.boot.actuate.trace.InMemoryTraceRepository实现的内存方式,始终保留最近的100条请求记录。
4.3 操作控制类
操作控制类端点拥有更强大的控制能力,如果要使用它们的话,需要通过属性来配置开启操作。
在原生端点中,只提供了一个用来关闭应用的端点:/shutdown。可以通过如下配置开启它:endpoints.shutdown.enabled=true
在配置了上述属性之后,只需要访问该应用的/shutdown端点就能实现关闭该应用的远程操作。由于开放关闭应用的操作本身是一件非常危险的事,所以真正在线上使用的时候,需要对其加入一定的保护机制,比如定制actuator 的端点路径、整合 Spring Security 进行安全校验等。