https://www.cnblogs.com/duanxz/p/3508267.html
前言
接着上一篇《Springboot Actuator之一:执行器Actuator入门介绍》actuator的介绍,继续深挖actuator中关于监控方面的特性。
Spring Boot包含很多其他的特性,它们可以帮你监控和管理发布到生产环境的应用。你可以选择使用HTTP端点,JMX或远程shell(SSH或Telnet)来管理和监控应用。审计(Auditing),健康(health)和数据采集(metrics gathering)会自动应用到你的应用。
执行器HTTP端点仅适用于基于Spring MVC的应用程序。
介绍
Metrics基本上是成熟公司里面必须做的一件事情,简单点来说就是对应用的监控,之前在一些技术不成熟的公司其实是不了解这种概念,因为业务跟技术是相关的 当业务庞大起来,技术也会相对复杂起来,对这些复杂的系统进行监控就存在必要性了,特别是在soa化的系统中,完整一个软件的功能分布在各个系统中,针对这些功能进行监控就更必要了 而Spring Boot Actuator 提供了metrics service,让监控变得统一化了,方便管理
开启production-ready特性
spring-boot-actuator模块提供了Spring Boot所有的production-ready特性。启用该特性的最简单方式就是添加对spring-boot-starter-actuator ‘Starter POM’的依赖。
执行器(Actuator)的定义:执行器是一个制造业术语,指的是用于移动或控制东西的一个机械装置。一个很小的改变就能让执行器产生大量的运动。
基于Maven的项目想要添加执行器只需添加下面的’starter’依赖:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
端点
执行器端点允许你监控应用及与应用进行交互。Spring Boot包含很多内置的端点,你也可以添加自己的。例如,health端点提供了应用的基本健康信息。
端点暴露的方式取决于你采用的技术类型。大部分应用选择HTTP监控,端点的ID映射到一个URL。例如,默认情况下,health端点将被映射到/health。
下面的端点都是可用的:
ID | 描述 | 敏感(Sensitive) |
---|---|---|
autoconfig | 显示一个auto-configuration的报告,该报告展示所有auto-configuration候选者及它们被应用或未被应用的原因 | true |
beans | 显示一个应用中所有Spring Beans的完整列表 | true |
configprops | 显示一个所有@ConfigurationProperties的整理列表 | true |
dump | 执行一个线程转储 | true |
env | 暴露来自Spring ConfigurableEnvironment的属性 | true |
health | 展示应用的健康信息(当使用一个未认证连接访问时显示一个简单的’status’,使用认证连接访问则显示全部信息详情) | false |
info | 显示任意的应用信息 | false |
metrics | 展示当前应用的’指标’信息 | true |
mappings | 显示一个所有@RequestMapping路径的整理列表 | true |
shutdown | 允许应用以优雅的方式关闭(默认情况下不启用) | true |
trace | 显示trace信息(默认为最新的一些HTTP请求) | true |
如果您使用Spring MVC,还可以使用以下附加端点:
ID | 描述 | 敏感默认值 |
---|---|---|
docs | 显示Actuator端点的文档,包括示例请求和响应。需要spring-boot-actuator-docs在类路径上 | false |
heapdump | 返回GZip压缩hprof堆转储文件。 | true |
jolokia | 通过HTTP暴露JMX bean(当Jolokia在类路径上时)。--《Spring Boot Actutaur + Telegraf + InFluxDB + Grafana 构建监控平台》 | true |
logfile | 返回日志文件的内容(if logging.file或logging.path属性已设置)。支持使用HTTP Range标头来检索部分日志文件的内容。 |
true |
根据端点是如何暴露的,该sensitive属性可以用作安全提示。例如,敏感端点在通过HTTP访问时将需要用户名/密码(或者如果Web安全性未启用,则简单地禁用)。
健康信息
健康信息可以用来检查应用的运行状态。它经常被监控软件用来提醒人们生产系统是否停止。health端点暴露的默认信息取决于端点是如何被访问的。对于一个非安全,未认证的连接只返回一个简单的’status’信息。对于一个安全或认证过的连接其他详细信息也会展示
健康信息是从你的ApplicationContext中定义的所有HealthIndicator beans收集过来的。Spring Boot包含很多auto-configured的HealthIndicators,你也可以写自己的。
安全与HealthIndicators
HealthIndicators返回的信息常常性质上有点敏感。例如,你可能不想将数据库服务器的详情发布到外面。因此,在使用一个未认证的HTTP连接时,默认只会暴露健康状态(health status)。如果想将所有的健康信息暴露出去,你可以把endpoints.health.sensitive设置为false。
为防止’拒绝服务’攻击,Health响应会被缓存。你可以使用endpoints.health.time-to-live属性改变默认的缓存时间(1000毫秒)。
自动配置的HealthIndicators
下面的HealthIndicators会被Spring Boot自动配置(在合适的时候):
名称 | 描述 |
---|---|
DiskSpaceHealthIndicator | 低磁盘空间检测 |
DataSourceHealthIndicator | 检查是否能从DataSource获取连接 |
MongoHealthIndicator | 检查一个Mongo数据库是否可用(up) |
RabbitHealthIndicator | 检查一个Rabbit服务器是否可用(up) |
RedisHealthIndicator | 检查一个Redis服务器是否可用(up) |
SolrHealthIndicator | 检查一个Solr服务器是否可用(up) |
可以使用该management.health.defaults.enabled 属性来禁用它们。
编写自定义HealthIndicators
想提供自定义健康信息,你可以注册实现了HealthIndicator接口的Spring beans。你需要提供一个health()方法的实现,并返回一个Health响应。Health响应需要包含一个status和可选的用于展示的详情。
import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.stereotype.Component; @Component public class MyHealth implements HealthIndicator { @Override public Health health() { int errorCode = check(); // perform some specific health check if (errorCode != 0) { return Health.down().withDetail("Error Code", errorCode).build(); } return Health.up().build(); } }
除了Spring Boot预定义的Status类型,Health也可以返回一个代表新的系统状态的自定义Status。在这种情况下,需要提供一个HealthAggregator接口的自定义实现,或使用management.health.status.order属性配置默认的实现。
例如,假设一个新的,代码为FATAL的Status被用于你的一个HealthIndicator实现中。为了配置严重程度,你需要将下面的配置添加到application属性文件中:
management.health.status.order: DOWN, OUT_OF_SERVICE, UNKNOWN, UP
如果使用HTTP访问health端点,你可能想要注册自定义的status,并使用HealthMvcEndpoint进行映射。例如,你可以将FATAL映射为HttpStatus.SERVICE_UNAVAILABLE。
info
应用程序信息显示从InfoContributor您定义的所有bean 收集的各种信息 ApplicationContext。Spring Boot包括一些自动配置 InfoContributors,您也可以自己编写。
自动配置的InfoContributors
以下内容InfoContributors由Spring Boot自动配置:
以下内容InfoContributors由Spring Boot自动配置:
名称 | 描述 |
---|---|
EnvironmentInfoContributor | 从钥匙Environment下方隐藏任何info钥匙。 |
GitInfoContributor | 如果git.properties文件可用,则显示git 信息。 |
BuildInfoContributor | 如果META-INF/build-info.properties文件可用,则显示构建信息。 |
自定义应用信息信息
通过设置Spring属性info.*,你可以定义info端点暴露的数据。所有在info关键字下的Environment属性都将被自动暴露。例如,你可以将下面的配置添加到application.properties:
info.app.name=MyService info.app.description=My awesome service info.app.version=1.0.0
在构建时期自动扩展info属性
你可以使用已经存在的构建配置自动扩展info属性,而不是对在项目构建配置中存在的属性进行硬编码。这在Maven和Gradle都是可能的。
使用Maven自动扩展属性
对于Maven项目,你可以使用资源过滤来自动扩展info属性。如果使用spring-boot-starter-parent,你可以通过@..@占位符引用Maven的’project properties’。
project.artifactId=myproject project.name=Demo project.version=X.X.X.X project.description=Demo project for info endpoint info.build.artifact=@project.artifactId@ info.build.name=@project.name@ info.build.description=@project.description@ info.build.version=@project.version@
注:在上面的示例中,我们使用project.*来设置一些值以防止由于某些原因Maven的资源过滤没有开启。Maven目标spring-boot:run直接将src/main/resources添加到classpath下(出于热加载的目的)。这就绕过了资源过滤和自动扩展属性的特性。你可以使用exec:java替换该目标或自定义插件的配置,具体参考plugin usage page。
如果你不使用starter parent,在你的pom.xml你需要添加(处于元素内):
<resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources>
和(处于内):
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.6</version> <configuration> <delimiters> <delimiter>@</delimiter> </delimiters> </configuration> </plugin>
Git提交信息
info端点的另一个有用特性是,当项目构建完成后,它可以发布关于你的git源码仓库状态的信息。如果在你的jar中包含一个git.properties文件,git.branch和git.commit属性将被加载。
对于Maven用户,spring-boot-starter-parent POM包含一个能够产生git.properties文件的预配置插件。只需要简单的将下面的声明添加到你的POM中:
<build> <plugins> <plugin> <groupId>pl.project13.maven</groupId> <artifactId>git-commit-id-plugin</artifactId> </plugin> </plugins> </build>
基于HTTP的监控和管理
果你正在开发一个Spring MVC应用,Spring Boot执行器自动将所有启用的端点通过HTTP暴露出去。默认约定使用端点的id作为URL路径,例如,health暴露为/health。
保护敏感端点
如果你的项目中添加的有Spring Security,所有通过HTTP暴露的敏感端点都会受到保护。默认情况下会使用基本认证(basic authentication,用户名为user,密码为应用启动时在控制台打印的密码)。
你可以使用Spring属性改变用户名,密码和访问端点需要的安全角色。例如,你可能会在application.properties中添加下列配置:
security.user.name=admin security.user.password=secret management.security.role=SUPERUSER
自定义管理服务器的上下文路径
有时候将所有的管理端口划分到一个路径下是有用的。例如,你的应用可能已经将/info作为他用。你可以用management.contextPath属性为管理端口设置一个前缀:
management.context-path=/manage
上面的application.properties示例将把端口从/{id}改为/manage/{id}(比如,/manage/info)。
自定义管理服务器的端口
对于基于云的部署,使用默认的HTTP端口暴露管理端点(endpoints)是明智的选择。然而,如果你的应用是在自己的数据中心运行,那你可能倾向于使用一个不同的HTTP端口来暴露端点。
management.port属性可以用来改变HTTP端口:
management.port=8081
由于你的管理端口经常被防火墙保护,不对外暴露也就不需要保护管理端点,即使你的主要应用是安全的。在这种情况下,classpath下会存在Spring Security库,你可以设置下面的属性来禁用安全管理策略(management security):
management.security.enabled=false
(如果classpath下不存在Spring Security,那也就不需要显示的以这种方式来禁用安全管理策略,它甚至可能会破坏应用程序。)
自定义管理服务器的地址
你可以通过设置management.address属性来定义管理端点可以使用的地址。这在你只想监听内部或面向生产环境的网络,或只监听来自localhost的连接时非常有用。
下面的application.properties示例不允许远程管理连接:
management.port=8081 management.address=127.0.0.1
配置特定于管理的SSL
配置为使用自定义端口时,管理服务器也可以使用各种management.ssl.*属性配置自己的SSL 。例如,这允许管理服务器通过HTTP可用,而主应用程序使用HTTPS:
server.port = 8443 server.ssl.enabled = true server.ssl.key-store = classpath:store.jks server.ssl.key-password = secret management.port = 8080 management.ssl.enable = false
或者,主服务器和管理服务器都可以使用SSL,但使用不同的密钥存储:
server.port = 8443 server.ssl.enabled = true server.ssl.key-store = classpath:main.jks server.ssl.key-password = secret management.port = 8080 management.ssl.enable = true management.ssl。 key-store = classpath:management.jks management.ssl.key-password = secret
禁用HTTP端点
如果不想通过HTTP暴露端点,你可以将管理端口设置为-1: management.port=-1
HTTP Health端点访问限制
通过health端点暴露的信息根据是否为匿名访问而不同。默认情况下,当匿名访问时,任何有关服务器的健康详情都被隐藏了,该端点只简单的指示服务器是运行(up)还是停止(down)。此外,当匿名访问时,响应会被缓存一个可配置的时间段以防止端点被用于’拒绝服务’攻击。endpoints.health.time-to-live属性被用来配置缓存时间(单位为毫秒),默认为1000毫秒,也就是1秒。
上述的限制可以被禁止,从而允许匿名用户完全访问health端点。想达到这个效果,可以将endpoints.health.sensitive设为false。
度量指标(Metrics)
Spring Boot执行器包括一个支持’gauge’和’counter’级别的度量指标服务。’gauge’记录一个单一值;’counter’记录一个增量(增加或减少)。同时,Spring Boot提供一个PublicMetrics接口,你可以实现它,从而暴露以上两种机制不能记录的指标。具体参考SystemPublicMetrics。
所有HTTP请求的指标都被自动记录,所以如果点击metrics端点,你可能会看到类似以下的响应:
{ "counter.status.200.root": 20, "counter.status.200.metrics": 3, "counter.status.200.star-star": 5, "counter.status.401.root": 4, "gauge.response.star-star": 6, "gauge.response.root": 2, "gauge.response.metrics": 3, "classes": 5808, "classes.loaded": 5808, "classes.unloaded": 0, "heap": 3728384, "heap.committed": 986624, "heap.init": 262144, "heap.used": 52765, "mem": 986624, "mem.free": 933858, "processors": 8, "threads": 15, "threads.daemon": 11, "threads.peak": 15, "uptime": 494836, "instance.uptime": 489782, "datasource.primary.active": 5, "datasource.primary.usage": 0.25 }
此处我们可以看到基本的memory,heap,class loading,processor和thread pool信息,连同一些HTTP指标。在该实例中,root(‘/’),/metrics URLs分别返回20次,3次HTTP 200响应。同时可以看到root URL返回了4次HTTP 401(unauthorized)响应。双asterix(star-star)来自于被Spring MVC /**匹配到的一个请求(通常为一个静态资源)。
gauge级别展示了一个请求的最后响应时间。所以,root的最后请求被响应耗时2毫秒,/metrics耗时3毫秒。
对 /metrics
接口提供的信息进行简单分类如下表:
分类 | 前缀 | 报告内容 |
---|---|---|
垃圾收集器 | gc.* | 已经发生过的垃圾收集次数,以及垃圾收集所耗费的时间,适用于标记-清理垃圾收集器和并行垃圾收集器(数据源自java.lang.management. GarbageCollectorMXBean) |
内存 | mem.* | 分配给应用程序的内存数量和空闲的内存数量(数据源自java.lang. Runtime) |
堆 | heap.* | 当前内存用量(数据源自java.lang.management.MemoryUsage) |
类加载器 | classes.* | JVM类加载器加载与卸载的类的数量(数据源自java.lang. management.ClassLoadingMXBean) |
系统 | processors、instance.uptime、uptime、systemload.average | 系统信息,例如处理器数量(数据源自java.lang.Runtime)、运行时间(数据源自java.lang.management.RuntimeMXBean)、平均负载(数据源自java.lang.management.OperatingSystemMXBean) |
线程池 | thread.* | 线程、守护线程的数量,以及JVM启动后的线程数量峰值(数据源自 java.lang .management.ThreadMXBean) |
数据源 | datasource.* | 数据源连接的数量(源自数据源的元数据,仅当Spring应用程序上下文里存在 DataSource Bean 的时候才会有这个信息) |
Tomcat 会话 | httpsessions.* | Tomcat的活跃会话数和最大会话数(数据源自嵌入式Tomcat的Bean,仅在使用嵌入式Tomcat服务器运行应用程序时才有这个信息) |
HTTP | counter.status._、gauge.response._ | 多种应用程序服务HTTP请求的度量值与计数器 |
解释说明:
-
请注意,这里的一些度量值,比如数据源和Tomcat会话,仅在应用程序中运行特定组件时才有数据。你还可以注册自己的度量信息。
-
HTTP的计数器和度量值需要做一点说明。counter.status 后的值是HTTP状态码,随后是所请求的路径。举个例子,counter.status.200.metrics 表明/metrics端点返回 200(OK) 状态码的次数。
-
HTTP的度量信息在结构上也差不多,却在报告另一类信息。它们全部以gauge.response 开头,,表明这是HTTP响应的度量信息。前缀后是对应的路径。度量值是以毫秒为单位的时间,反映了最近处理该路径请求的耗时。
-
这里还有几个特殊的值需要注意。root路径指向的是根路径或/。star-star代表了那些Spring 认为是静态资源的路径,包括图片、JavaScript和样式表,其中还包含了那些找不到的资源。这就是为什么你经常会看到 counter.status.404.star-star,这是返回了HTTP 404 (NOT FOUND) 状态的请求数。
-
/metrics
接口会返回所有的可用度量值,但你也可能只对某个值感兴趣。要获取单个值,请求时可以在URL后加上对应的键名。例如,要查看空闲内存大小,可以向/metrics/mem.free
发一 个GET请求。例如访问:http://localhost:8088/monitor/metrics/mem.free
,返回:{"mem.free":178123}
。
系统指标
Spring Boot暴露以下系统指标:
- 系统内存总量(mem),单位:Kb
- 空闲内存数量(mem.free),单位:Kb
- 处理器数量(processors)
- 系统正常运行时间(uptime),单位:毫秒
- 应用上下文(就是一个应用实例)正常运行时间(instance.uptime),单位:毫秒
- 系统平均负载(systemload.average)
- 堆信息(heap,heap.committed,heap.init,heap.used),单位:Kb
- 线程信息(threads,thread.peak,thead.daemon)
- 类加载信息(classes,classes.loaded,classes.unloaded)
- 垃圾收集信息(gc.xxx.count, gc.xxx.time)
数据源指标
Spring Boot会为你应用中定义的支持的DataSource暴露以下指标:
- 最大连接数(datasource.xxx.max)
- 最小连接数(datasource.xxx.min)
- 活动连接数(datasource.xxx.active)
- 连接池的使用情况(datasource.xxx.usage)
所有的数据源指标共用datasoure.前缀。该前缀对每个数据源都非常合适:
-
如果是主数据源(唯一可用的数据源或存在的数据源中被@Primary标记的)前缀为datasource.primary
-
如果数据源bean名称以dataSource结尾,那前缀就是bean的名称去掉dataSource的部分(例如,batchDataSource的前缀是datasource.batch)
- 其他情况使用bean的名称作为前缀
通过注册一个自定义版本的DataSourcePublicMetrics bean,你可以覆盖部分或全部的默认行为。默认情况下,Spring Boot提供支持所有数据源的元数据;如果你喜欢的数据源恰好不被支持,你可以添加另外的DataSourcePoolMetadataProvider beans。具体参考DataSourcePoolMetadataProvidersConfiguration。
缓存指标
为应用程序中定义的每个受支持的缓存显示以下度量标准:
- 当前大小的缓存(cache.xxx.size)
- 命中率(cache.xxx.hit.ratio)
-
比例(cache.xxx.miss.ratio)
缓存提供商不会以一致的方式暴露命中/失误率。虽然有些暴露了一个聚合值(即自上次统计数据被清除以来的命中率),但是其他人暴露了一个时间值(即最后一秒的命中率)。检查您的缓存提供程序文档以获取更多详细信息。
如果两个不同的缓存管理器碰巧定义相同的缓存,则缓存的名称以CacheManagerbean 的名称为前缀。
可以通过使用自定义版本注册一个bean来覆盖部分或全部默认值CachePublicMetrics。默认情况下,Spring Boot为EhCache,Hazelcast,Infinispan,JCache和Guava提供缓存统计信息。CacheStatisticsProvider如果您最喜欢的缓存库不支持开箱即可添加其他 bean。参见CacheStatisticsAutoConfiguration例子。
/dump:该端点用来暴露程序运行中的线程信息。
它使用java.lang.management.ThreadMXBean的dumpAllThreads方法来返回所有含有同步信息的活动线程详情。
/trace:该端点用来返回基本的HTTP跟踪信息。
默认情况下,跟踪信息的存储采用org.springframework.boot.actuate.trace.InMemoryTraceRepository实现的内存方式,始终保留最近的100条请求记录。
操作控制类
仔细的读者可能会发现,我们在“初识Actuator”时运行示例的控制台中输出的所有监控端点,已经在介绍应用配置类端点和度量指标类端点时都讲解完了。那么还有哪些是操作控制类端点呢?
实际上,由于之前介绍的所有端点都是用来反映应用自身的属性或是运行中的状态,相对于操作控制类端点没有那么敏感,所以他们默认都是启用的。
而操作控制类端点拥有更强大的控制能力,如果要使用它们的话,需要通过属性来配置开启。在原生端点中,只提供了一个用来关闭应用的端点:/shutdown。我们可以通过如下配置开启它:
endpoints.shutdown.enabled=true
在配置了上述属性之后,只需要访问该应用的/shutdown端点就能实现关闭该应用的远程操作。
由于开放关闭应用的操作本身是一件非常危险的事,所以真正在线上使用的时候,我们需要对其加入一定的保护机制,比如:定制Actuator的端点路径、整合Spring Security进行安全校验等。
Tomcat session指标
如果你使用Tomcat作为内嵌的servlet容器,session指标将被自动暴露出去。 httpsessions.active和httpsessions.max提供了活动的和最大的session数量。
记录自己的指标
想要记录你自己的指标,只需将CounterService或GaugeService注入到你的bean中。CounterService暴露increment,decrement和reset方法;GaugeService提供一个submit方法。
下面是一个简单的示例,它记录了方法调用的次数:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.metrics.CounterService; import org.springframework.stereotype.Service; @Service public class MyService { private final CounterService counterService; @Autowired public MyService(CounterService counterService) { this.counterService = counterService; } public void exampleMethod() { this.counterService.increment("services.system.myservice.invoked"); } }
注:你可以将任何的字符串用作指标的名称,但最好遵循所选存储或图技术的指南。Matt Aimonetti’s Blog中有一些好的关于图(Graphite)的指南。
添加你自己的公共指标
想要添加额外的,每次指标端点被调用时都会重新计算的度量指标,只需简单的注册其他的PublicMetrics实现bean(s)。默认情况下,端点会聚合所有这样的beans,通过定义自己的MetricsEndpoint可以轻易改变这种情况。
追踪(Tracing)
对于所有的HTTP请求Spring Boot自动启用追踪。你可以查看trace端点,并获取最近一些请求的基本信息:
[{ "timestamp": 1394343677415, "info": { "method": "GET", "path": "/trace", "headers": { "request": { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Connection": "keep-alive", "Accept-Encoding": "gzip, deflate", "User-Agent": "Mozilla/5.0 Gecko/Firefox", "Accept-Language": "en-US,en;q=0.5", "Cookie": "_ga=GA1.1.827067509.1390890128; ..." "Authorization": "Basic ...", "Host": "localhost:8080" }, "response": { "Strict-Transport-Security": "max-age=31536000 ; includeSubDomains", "X-Application-Context": "application:8080", "Content-Type": "application/json;charset=UTF-8", "status": "200" } } } },{ "timestamp": 1394343684465, ... }]
自定义追踪
如果需要追踪其他的事件,你可以将一个TraceRepository注入到你的Spring Beans中。add方法接收一个将被转化为JSON的Map结构,该数据将被记录下来。
默认情况下,使用的InMemoryTraceRepository将存储最新的100个事件。如果需要扩展该容量,你可以定义自己的InMemoryTraceRepository实例。如果需要,你可以创建自己的替代TraceRepository实现。
进程监控
在Spring Boot执行器中,你可以找到几个创建有利于进程监控的文件的类:
- ApplicationPidFileWriter创建一个包含应用PID的文件(默认位于应用目录,文件名为application.pid)
- EmbeddedServerPortFileWriter创建一个或多个包含内嵌服务器端口的文件(默认位于应用目录,文件名为application.port)
默认情况下,这些writers没有被激活,但你可以使用下面描述的任何方式来启用它们。
扩展属性
你需要激活META-INF/spring.factories文件里的listener(s):
org.springframework.context.ApplicationListener= org.springframework.boot.actuate.system.ApplicationPidFileWriter, org.springframework.boot.actuate.system.EmbeddedServerPortFileWriter
以编程方式
你也可以通过调用SpringApplication.addListeners(…)方法来激活一个监听器,并传递相应的Writer对象。该方法允许你通过Writer构造器自定义文件名和路径。
--------------------- 本文来自 等风de帆 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/l_sail/article/details/70495601?utm_source=copy