SpringBoot项目中常见组件的配置属性

1. 配置属性清单

1.1 日志配置

序号属性名类型用途备注
1debugbool开启debug日志级别仅在没有自定义logback的情况下有效
2tracebool开启trace日志级别仅在没有自定义logback的情况下有效
3logging.configstring日志配置文件的路径比如,loggin.config=classpath:logback.xml 就可以指定logback日志的配置
4logging.filestring指定日志文件名比如:logging.file=my-app.log
5logging.pathstring指定日志文件的目录比如,logging.path=/var/log
6logging.file.max-historynumber日志文件最大存档数量假如设置为10,表明最多保留10个日志文件,如果超过10个,则会删除旧的
该配置仅在没有自定义logback的情况下有效
7logging.file.max-sizestring单个日志文件的最大容量如10MB,512KB等
该配置仅在没有自定义logback的情况下有效
8logging.level.*string指定某个logger的级别假如要将所有spring组件的日志级别设置为debug,则可以这样配置:
logging.level.org.springframeword=debug
9logging.group.*string将多个logger分组假如要将 org.springfraework 和 org.apache 两个 logger 合并为一组,名为 public,可如下配置:
logging.group.public=org.springfraework, org.apache
10logging.pattern.consolestring控制台日志样式设置仅在没有自定义logback的情况下有效
11logging.pattern.dateformatstring日志中的日期输出格式如:yyyy-MM-dd HH:mm:ss.SS
仅在没有自定义logback的情况下有效
12logging.register-shutdown-hookbool是否要在日志组件启动后,注册“系统退出”的回调函数
13logging.pattern.levelstring指定日志输出格式中,与日志等级相关的信息如何输出默认值为:%5p
仅在没有自定义logback的情况下有效
涉及的格式字符如下:
 %p : 用一个字母来标识日志级别,例如D表示DEBUG,I表示INFO
 %5p :最多用五个字母的来标识日志级别,例如DEBUG或INFO.
 %.-5p :固定用五个字母的日志级别,如果不足五个字符则向左对齐,例如DEBUG或INFO
 %t :输出线程名称
 %c :输入Logger的名称(简单类名)
 %C :Logger的唯一名称(全限定类名)

要求:最多5个字母显示日志级别,并且包含线程名称和类名,其配置如下:
logging.pattern.level=%5p [%t] %c{1.} -
14logging.exception-conversion-wordstring指定如何输出异常对象默认值为:%wEx
只能配置预定义的几种形式,如下所示:
 %wEx :完整堆栈轨迹,包括异常类、异常信息和详细堆栈跟踪
 %wEx{short} :简短堆栈轨迹,仅包括异常类和异常信息,省略详细堆栈跟踪
 %wEx{full} :完整堆栈轨迹,包括异常类、异常信息和详细堆栈跟踪
 %wEx{none} :不输出任何异常信息

上面提到的仅在没有自定义logback的情况下有效的说法并不严谨,但这种说法适合日常开发中的大多数情况。严格来讲,spring boot 启动后,有一套默认的logback配置,上述有此备注的属性,是单独针对这个默认的logback配置的。如果工程中还单独配置了logback, 则spring boot默认的logback就不载了。但依然可以在自己的logback配置中,把 spring boot 默认的日志配置加载进来,但几乎很少有项目这样做,或是不知道有此特性。

1.2 指定配置文件位置

配置文件的配置由两部分构成:目录 + 文件名,如: /etc/config/apps/application.yml 中, /etc/config/apps/ 为目录,application.yml 为文件名,因此相应的配置也分成这两部分

序号属性名类型用途备注
1spring.config.namestring配置文件的文件名
2spring.config.locationstring配置文件的目录可以指定多个目录,使用英文逗号(,) 分隔。通常目录由协议和路径构成,比如:
a. file:///etc/ : 代表文件系统目录,但由于太常用,可简写为/etc
b. classpath:/config : 代表jar包内部目录
c. http://config.com/config : 代表网络目录,这其实最常用,但通常由配置服务内部完成

特别说明:如果配置的内容不是一个目录,而是完整的文件名,则读取此文件
3logging.config.additional-locationstring附加的配置文件目录同上,可以指定多个目录,使用英文逗号(,) 分隔,如:
logging.config.additional-location=/etc/config/extra,/var/config/extra
除了标准目录外,该参数指定的目录下的配置文件,也会被读取
4spring.autoconfigure.excludestring要排除的自动装配Java类多个排除项用英文逗号分隔,比如:
spring.autoconfigure.exclude=com.alibaba.cloud.nacos.NacosConfigAutoConfiguration

部分新手会有个疑惑:property属性配置项,不是写在配置文件里边的么,我在配置文件里边再写“配置文件的目录和名称”感觉怪怪的,他能起作用吗?
当然仔细一推敲就会发现这个问题本身就有问题 😄 。这涉及到 spring boot 启动时应该去哪里读取配置属性的问题。
很明显,配置文件的位置就是根据上面3个属性指定的。有趣的是,上面3个属性也是 properties 的一部分,可是现在都还没有加载和读取配置文件,哪里来的 properties 呢?此时的 properties 应该是为空的。

没错,此时确实还没加载配置文件,那么上面的3个属性从哪里获取的呢?这是3个特殊的配置属性,它不来自配置文件,而是来自程序默认值 或 启动程序时的命令行参数 或 Java系统属性 或 操作系统环境变量

比如有一个名为my-app.jar的spring boot程序:

  • java -jar my-app.jar
    配置文件为classpath:/application.yml 或 classpath:/application.properties

  • java -jar my-app.jar --spring.config.location=/etc/config
    配置文件为 /etc/config/application.yml 或 /etc/config/application.properties

  • java -Dspring.config.location=/etc/config -jar my-app.jar
    配置文件为 /etc/config/application.yml 或 /etc/config/application.properties

这也是一个十分常见的范式,比如:不同于其它进程的守护进程,不同于其它用户的“超级管理员”,docker中不同于其它进程的“1号管理进程”

1.3 Boot应用程序自身的配置

序号属性名类型用途备注
1spring.application.namestring应用程序的名字在 Cloud 环境下,也是微服务的名字
2spring.application.admin.enabledbool是否开启管理功能默认值:false
开启此选项后,SpringBoot 将开放后台管理的RESTFull接口,用于查看健康状态、环境配置、线程等信息
可访问 /acuator 来查看以上信息
3spring.application.admin.jmx-namestring远程管理的 MBean 名称默认值为:org.springframework.boot:type=Admin,name=SpringApplication
4spring.main.sourcesstringBoot应用程序的资源文件或目录所谓资源,是指 ApplicationContext要加载的类名、包、或基于 Xml 配置的Bean定义文件
比如:在application.properties文件中有如下配置:
 spring.main.resources=vip.guzb.MyApplication,com.eastknight.config
上述配置指明SpringBoot引导时,将MyApplication作为启动类,并加载com.eastknight.config包下的配置

SpringBoot程序启动时,首先是去找资源文件,然后根据boot约定的规则读取资源文件,并根据文件中组件的装配要求加载组件
因此,也可以通过命令行参数来指定这个配置项,比如:
 java -jar my-app.jar --spring.main.resources=vip.guzb.MyApplication
5spring.main.banner-modestring启动时的banner信息默认值为 console, 取值列表如下:
 off : 禁用banner功能
 console : 将 banner 内容输出到命令行窗口
 log : 将 banner 内容输出到应用程序的日志中

还可以通过编程的方式来细粒度地设置banner
6spring.main.web-application-typestring指定 web 应用的类型支持以下三种内容:
 SERVLET : 即常见的基于阻塞式IO模型的Web服务
 REACTIVE : 适用于高并发、高吞吐量的,基于异步IO模型的反应堆式Web应用程序,在Spring当前的体系中,就是WebFlux
 NONE : 非WEB应用程序,例如批处理任务或后台作业

如果不明确指定应用类型,Spring Boot 会根据 classpath 下的类和已加载 Configuration 进行推定
7spring.main.register-shutdown-hookbool应用程序是否注册“系统退出”回调默认值:true
8spring.main.allow-bean-definition-overridingbool是否允许重复定义Bean默认值:false
如果为true, 则允许在读取“Bean定义”期间,出现多个相同名称的Bean定义,后加载的覆盖先加载的。

1.4 服务器配置

1.4.1 服务器基础配置

序号属性名类型用途备注
1server.portnumber网络监听端口默认值:8080
2server.addressstring服务器监听的网络地址有以下三种设置类型
空值 : 这也是默认值,表示绑定当前主机所有可用的网络地址
具体的IP地址 :如192.168.10.125
主机名 :如 vip.guzb
3server.server-headerstringHTTP 响应头中“Server”字段的内容如:Tomcat 10.1.11
4server.max-http-header-sizestringHTTP 响应头的最大内容大小默认为 8KB
5server.use-forward-headersbool是否使用X-Forwarded-*转发的头部信息默认为 false , 这表头Jetty默认不使用代理服务器转发的头信息
6server.compression.enabledbool是否开启响应(response)压缩默认值:false
多数生产环境的 spring boot Web应用程序,其http请求都会经过 nginx 转发,nginx 默认会对响应数据进行压缩
7server.compression.excluded-user-agentsstring指定不压缩响应数据的客户端名称多个客户端用英文豆号分隔,比如:
apache http client,edage 112.0.1722.48,chrome 114.0.5735.110
8server.compression.mime-typesstring对哪些MIME类型的内容进行压缩如:text/html,text/plain,text/css,text/javascript,application/json
9server.compression.min-response-sizestring超过多少体积的内容才进行压缩如:2KB
10server.error.include-exceptionbool错误页面的内容是否包含异常默认为 false
11server.error.include-stacktracebool错误页面的内容是否包含异常堆栈默认为false 或 never
12server.error.pathstring错误页面对的Web Controller 路径默认为 /error
13server.error.whitelabel.enabledbool是否开启默认的错误信息显示页面默认为 true
14server.connection-timeoutnumberWeb服务器的网络连接器接收下一个Http请求的最大等待时长单位:毫秒,默认行为是取具体服务器(如tomcat、jetty)的Connector默认值
设置为 -1 代表可无限等待
15server.http2.enabledbool是否支持 HTTP2 协议默认为 ture, 当前使用最多的还是 HTTP 1.1
16server.ssl.enabledbool是事支持 SSL 协议默认为 ture, 但实践中,更多将SSL配置到了 nginx 上
17server.ssl.enabled-protocolsstring支持的 SSL 协议清单多个协议用英文逗号分隔,常见的 SSL/TLS 协议版本如下:
1. SSLv3 :已经过时且不推荐使用,存在多个安全漏洞
2. TLSv1.0 / TLSv1.1 :较老的协议版本,已经被广泛认为不够安全
3. TLSv1.2 :当前广泛使用的安全协议版本
4. TLSv1.3 :最新的 TLS 协议版本,提供更强的安全性和性能改进
18server.ssl.protocolstring服务器使用的 SSL 协议默认为 TLS
19server.ssl.ciphersstringSSL 协议的加密套件多个加密套件用英文逗号分隔,最常用的加密套件如下:
1. AES(Advanced Encryption Standard):一种对称加密算法,包括 AES128、AES256 等不同密钥长度
2. DES(Data Encryption Standard):一种早期的对称加密算法,已经被 AES 取代
3. RSA(Rivest, Shamir, Adleman):一种非对称加密算法,用于密钥交换和数字签名
4. SHA(Secure Hash Algorithm):哈希算法,用于生成消息摘要,包括 SHA-256、SHA-384 等不同摘要长度
4. ECDHE(Elliptic Curve Diffie-Hellman Ephemeral):一种基于椭圆曲线的密钥交换算法,提供前向安全性
20server.ssl.client-authstringSSL的客户端认证模式默认为none, 取值列表如下:
1. none : 服务器不要求客户端进行身份验证,并且可以继续建立连接
2. want : 服务器希望客户端提供有效的证书进行身份验证,但即使客户端没有提供证书,连接也会继续建立
3. need : 服务器要求客户端提供有效的证书进行身份验证。如果客户端没有提供有效的证书,连接将被终止
22server.ssl.key-aliasstring指定密钥在服务器密钥库中的别名
22server.ssl.key-passwordstring服务器访问密钥时所需的密码
23server.ssl.key-storestring指定服务器中 SSL/TLS 密钥库的路径
24server.ssl.key-store-passwordstring服务器访问 SSL/TLS 密钥库时所需的密码
25server.ssl.key-store-providerstringSSL/TLS 密钥库供应商的名称实际上就是密钥库程序的名称,主要有 SUN 和 BC (Bouncy Castle)
26server.ssl.key-store-typestringSSL/TLS 密钥库的类型默认为:JKS,密钥类型用于定义如何存储密钥,常用的类型有:
1. JKS :Java KeyStore 是 Java 平台默认的密钥库类型
2. PKCS12 :基于 RSA 公钥加密标准(PKCS)#12 的密钥库类型
3. BKS :Bouncy Castle 密钥库类型
4. UBER :BC-FKS,Bouncy Castle 密钥库类型的兼容版本
27server.ssl.trust-storestring信任密钥库的位置
28server.ssl.trust-store-passwordstring访问信任密钥库的密码
29server.ssl.trust-store-providerstring信任密钥库的程序提供商同 server.ssl.key-store-provider
30server.ssl.trust-store-typestring信任密钥库的的类型同 server.ssl.key-store-type
31server.netty.connection-timeoutnumbernetty通道的连接超时时长单位:毫秒。仅当Servlet服务器的网络部分使用Netty时有效

1.4.2 Tomcat 服务器配置

序号属性名类型用途备注
1server.tomcat.basedirstringTomcat运行时使用的根目录配置、日志、临时文件等资源的位置,默认为空,一般情况下不设置该属性
2server.tomcat.uri-encodingstringURL的编码类型默认为:UTF-8
3server.tomcat.accept-countnumber最大请求的排队数默认为 100
当所有处理请求的线程均处于忙碌状态时,后续请求将进入队列。如果队列也已满,则拒绝连接
4server.tomcat.max-connectionsnumber最大请求连接数默认为 10000
5server.tomcat.max-threadsnumber最大工作线程数默认为 200
工作线程即具体执行Web请求的线程
6server.tomcat.min-spare-threadnumber最小工作线程数默认为 10
7server.tomcat.max-swallow-sizenumber单个请求可接收的最大消息体大小默认为 2M
8server.tomcat.remote-ip-headerstring获取原始请求客户端IP的HTTP Header字段名在业务代码中,可以通过 request.getRemoteAddr() 方法获取请求端的地址信息。
但Tomcat是如何保证这个方法获取到的地址是真实的请求客户端的地址呢,如果中间经过nginx代理服务器转发呢?
方法是通过读取http header中的字段,通常代理服务器都会将他所代理的请求客户端的IP写到header的某个字段中,不同的代理服务器,使用的字段名可能不同,但最常见的是以下两个:
1. X-Forwarded-For
2. X-Real-IP
9server.tomcat.protocol-headerstring读取原始请求客户端 http 协议名的header字段用途同上,tomcat从header的这个字段名上读取原始的http协议名
该字段名通常为:X-Forwarded-Proto
10server.tomcat.resource.cache-ttlnumber静态资源文件的缓存时长单位:秒,静态资源如:.css 、.js 、.jpg 等文件
11server.tomcat.use-relative-redirectsbool重定向折url是否使用相对地址默认为 false
如果访问请求经过了中间代理,使用绝对地址的话,会出现无法访问的问题
12server.tomcat.background-processor-delaynumberTomcat 后台任务处理器的执行间隔单位:秒
如清理session 、异步调用等后台操作
13server.tomcat.additional-tld-skip-patternsstring设置要忽略的TLD处理Jar包的名称样式满足名称样式的TLD jar包将不被加载,以提高性能
TLD(Tag Library Descriptor) 标签库描述符是早期 JSP 体系的一种处理标签的Java库,在前后端分离的应用中,它已经没有用武之地了
14server.tomcat.internal-proxiesstring内部代理的IP地址样式是一个正则表达式
示例:10\.\d{1,3}\.\d{1,3}\.\d{1,3}
当客户端的IP地址匹配该样式时,被认定为是内部代理服务器的地址,因此它不是真实的客户端IP地址,Tomcat 将通过从header中读取字段等方法来尝试获取真实的客户端IP地址

默认值:10\.\d{1,3}\.\d{1,3}\.\d{1,3}|\192\.168\.\d{1,3}\.\d{1,3}|\169\.254\.\d{1,3}\.\d{1,3}|\127\.\d{1,3}\.\d{1,3}\.\d{1,3}|\172\.1[6-9]{1}\.\d{1,3}\.\d{1,3}|\172\.2[0-9]{1}\.\d{1,3}\.\d{1,3}|\172\.3[0-1]{1}\.\d{1,3}\.\d{1,3}\0:0:0:0:0:0:0:1\::1
15server.tomcat.redirect-context-rootbool是否在重定向URL上添加应用上下文路径默认值为 true
对于 SpringBoot 这种基于内嵌 Tomcat 形式的程序,可忽略此特性

Tomcat 标准的 Servlet 容器,它支持同时部署多个 Web 应用,每个应用都有各自的应用上下文。体现在URL上就是前缀,比如部署了两个应用,分别是 shop 和 order, 如果它们都提供了address接口,则访问应用时,就需要加上下文前缀,变成了 /shop/address 和 /order/address。
如果在shop应用中返回了一个到order应用的重定向地址 /order/details, 如果 server.tomcat.redirect-context-root=true, 则实际返回的重向地址为:/shop/order/details
16server.tomcat.accesslog.enabledbool是否开启访问日志记录默认为 false
17server.tomcat.accesslog.directorystring访问日志的存放目录默认为 logs
如果是相对目录,则相对的是批tomcat的主目录,也可以指定绝对路径
18server.tomcat.accesslog.bufferedbool是否缓存访问日志,以定期批量刷新默认为 true
19server.tomcat.accesslog.prefixstring日志文件名的前缀默认为 access_log.
20server.tomcat.accesslog.suffixstring日志文件的后缀名默认为 .log
21server.tomcat.accesslog.file-date-formatstring访问日志文件名中的日期格式默认为 .yyyy-MM-dd, 实际效果就是日志文件的动态中缀
22server.tomcat.accesslog.patternstring访问日志内容格式默认为:common
common是一个预定义好的格式别名,真实的格式是由一系列格式字符组成的,如:%h %l %u %t "%r" %s %b

1. %a : 远程IP地址
2. %A : 本地IP地址
3. %b :发送的字节数,不包括HTTP头,没有发送字节就显示为 -
4. %B : 发送的字节数,不包括HTTP头
5. %h : 远程主机名
6. %H : 请求协议
7. %l : (是小写的L)远程逻辑从identd的用户名(总是返回 - )
8. %m : 请求方法
9. %p : 本地端口
10. %q : 查询字符串(如果有查询参数的话,会在前面加 ? 字符,反之为空)
11. %r : 第一行的要求
12. %s : 响应的HTTP状态代码
13. %S : 用户会话ID
14. %t : 日期和时间,在通用日志格式
15. %u : 远程用户身份验证
16. %U : 请求的URL路径
17. %v : 本地服务器名
18. %D : 处理请求的时间(以毫秒为单位)
19. %T : 处理请求的时间(以秒为单位)
20. %I :(是大写的i)当前请求的线程名称
23server.tomcat.accesslog.rename-on-rotatebool是否通过重命名当前日志文件的方式来存档当前日志默认为 false
tomcat 会根据时间和当前日志文件大小,判定是否应该将当前日志存档

1.4.3 Undertow 服务器配置

序号属性名类型用途备注
1server.undertow.buffer-sizestring请求和响应的缓冲区大小如:2MB,512KB 等,纯数字的话,单位为字节
2server.undertow.direct-buffersbool是否在 JVM 的堆外直接申请缓冲内存默认是不申请堆外缓冲内存的
3server.undertow.eager-filter-initbool是否在启用时加载 Servlet 过滤器默认为 false
这样可快速启动应用,只有当收到真实请求后,才会初始化 Servlet 过滤器
4server.undertow.io-threadsnumber接收Web请求的主线程数默认为操作系统CPU核心数,主线程只负责接收请求,不负责处理请求,处理请求的是工作线程
5server.undertow.worker-threadsnumber处理Web请求的工作线程数默认为IO线程数(server.undertow.io-threads)的8
6server.undertow.max-http-post-sizenumberPost请求的body最大负载量默认为 -1B
可以是一个纯数字,也可以是数字+单位,如:10MB、512KB等。
-1 代表body大小不受限制
7server.undertow.no-request-timeoutnumber关闭连接的最大空闲时间单位:毫秒
当一个WEB连接建立后,却不发送任何后续请求时,该连接处于空闲状态,当这个空闲时长达到指定长度后,连接会被关闭
8server.undertow.accesslog.dirstring访问日志的目录
9server.undertow.accesslog.enabledbool是否开启访问日志记录默认为 false
10server.undertow.accesslog.patternstring访问日志的内容格式默认为 common,它的配置格式与 server.tomcat.accesslog.pattern 一样
11server.undertow.accesslog.prefixstring访问日志文件名的前缀默认为 access_log.
12server.undertow.accesslog.suffixstring访问日志文件名的后缀默认为 .log
13server.undertow.accesslog.rotatebool是否开启日志文件的轮转功能默认为 false
轮转功能是指:当日志的内容大小和日期达到一定要求后,将该部分日志切割成一个单独的文件存档

1.4.4 Jetty 服务器配置

序号属性名类型用途备注
1server.jetty.acceptorsnumber接收WEB请求的接收器(线程)数量默认为 -1
-1 表示请求接收器的数量将根据操作系统的的硬件特性而定,通常是CPU核心数的一多半
2server.jetty.selectorsnumber处理WEB请求的选择器(线程)数量默认为 -1
-1 表示请求选择器的数量将根据操作系统的的硬件特性而定
3server.jetty.max-http-post-sizenumberHttp Post 请求的body部分的最大容量默认为 200000 字节
4server.jetty.connection-idle-timeoutnumber关闭连接的最大空闲时间单位:毫秒
当一个WEB连接建立后,却不发送任何后续请求时,该连接处于空闲状态,当这个空闲时长达到指定长度后,连接会被关闭
5server.jetty.accesslog.enabledbool是否开启访问日志的记录功能默认为 false
6server.jetty.accesslog.appendbool是否以“追加”方式记录访问日志默认为 false
这里的“追加”是指服务器启动后,新的日志将在原来(启动前)的日志文件上追加新日志。如果为false, 则会直接覆盖旧的日志内容。但本次运行期间产生的日志内容,并不会存在覆盖一说
7server.jetty.accesslog.date-formatstring设置记录访问日志的日期格式默认为 dd/MMM/yyyy:HH:mm:ss Z
8server.jetty.accesslog.extended-formatbool是否启用访问日志的扩展记录格式默认为 false,
扩展格式会记录更多的客户端信息
9server.jetty.accesslog.filenamestring访问日志的文件名默认为 access.log
多数日志文件名配置都支持以下配置约定:
1. 仅指定文件名:日志文件将保存在服务器的工作目录中, 如:server.jetty.accesslog.filename = access.log
2. 指定相对路径: 相对路径依然针对的是服务器工作目录,如:server.jetty.accesslog.filename = logs/access.log 会将日志文件保存在 logs 目录下
3. 指定绝对路径: 直接指定完整的文件路径,如:server.jetty.accesslog.filename = /var/log/myapp/access.log
10server.jetty.accesslog.localestring指定访问日志的Locale默认为操作系统的locale
11server.jetty.accesslog.log-cookiesbool是否记录Web请求的 cookie 信息默认为 false
12server.jetty.accesslog.log-latencybool访问日志中,是否记录请求的处理时间(延迟时间)默认为 false
处理时间是指 request -> response 之间的时长
13server.jetty.accesslog.log-serverbool访问日志,是否记录请求端的主机名默认为 false

1.4.5 Servlet 配置

序号属性名类型用途备注
1server.servlet.context-pathstring设置Servlet服务的请求上下文路径从使用上讲,就是在请求这个Servlet的时候,需在url上加前缀,前缀内容就是这个context-path
2server.servlet.context-parameters.*string添加ServletContext的初始化参数对应于传统web.xml配置中的<init-param>标签,比如有这面这样一组初始化参数:
<init-param>
  <param-name>email</param-name>
  <param-value>east-knight@codefate.net<param-value>
<init-param>
这组标签通过spring property 来配置的话,结果如下:
server.servlet.context-parameters.email=east-knight@codefate.net
3server.servlet.application-display-namestring整个Servelt应用的名称该名称通常显示在相应的Servlet容器(服务器)的管理页面中,业务开发中使用不到
4server.servlet.jsp.class-namestring处理 JSP 视图的类名JSP 是一种视图模板技术,在模板中可以让代码与html标签混合使用,它是Servlet的一种升级使用方式。原始的 Servlet 只提供了向 Reponse 中写入字符串或数据流的底层功能
5server.servlet.jsp.init-parameters.*string为JSP Servelt指定初始化参数与 server.servlet.context-parameters.* 类似
6server.servlet.jsp.registeredbool指定JSP Servlet 是否已经注册了默认为 true
7server.servlet.session.cookie.namestring会话 Cookie 的名称
8server.servlet.session.cookie.commentstring为会话 Cookie 设置注释
9server.servlet.session.cookie.domainstring设置会话 Cookie 适用的域名如果指定了域名,则只会对来自该域名的客端才能读取cookie
10server.servlet.session.cookie.pathstring指定哪些 path 开始会话 Cookie比如指定 server.servlet.session.cookie.path=/user , 则只有 /user 开头的页面脚本才能读取 cookie
11server.servlet.session.cookie.http-onlybool是否开启cookie的http-only特性如果开启,页面脚本无法读取cookie. 事实上在前后分离架构下,已经不使用cookie了
12server.servlet.session.cookie.securebool是否仅在https协下开启 Cookie默认为 false
13server.servlet.session.cookie.max-agenumber会话 cookie 的最大存活时长单位:秒。如果不指定,则关闭浏览器后自动过期
14server.servlet.session.timeoutnumber会话的过期时长默认为 30m, 即30分钟,如果不指定时间单位后缀,则默认为单位为:秒
15server.servlet.session.tracking-modesstring会话的跟踪模式即如何实现session的ID传递,可以配置多个会话跟踪模式,它们之间使用英文逗号分隔。支持的模式有:
1. COOKIE : 通过客户端cookie跟踪,会话ID保存在Cookie中
2. URL : 通过URL跟踪,会话ID保存在URL的Query参数中
3. SSL : 要求在安全连接(HTTPS)下才能创建会话
1. NONE : 禁用会话追踪,会话标识符不会被创建或传输
16spring.servlet.multipart.enabledbool是否启用多部件上传功能默认为 true
17pring.servlet.multipart.file-size-thresholdnumber设置写入磁盘的文件大小阈值默认为 0, 单位:字节。当上传文件大小超该阈值时,会将文件写入到磁盘
18spring.servlet.multipart.locationstring上传文件的临时保存位置
19spring.servlet.multipart.max-file-sizenumber单个文件的最大容量默认为 1M
20spring.servlet.multipart.max-request-sizenumber多部件 http 请求的最大容量默认为 10M
21spring.servlet.multipart.resolve-lazilybool是否延迟解析多部件消息体默认为 false
如果设置为true, 则只有程序中真实调用了获取部件体内容的方法时,才会去解析 ,这可以提高性能

1.5 数据源配置

1.5.1 默认JDBC配置

序号属性名类型用途备注
1spring.datasource.namestring数据源名称当使用内存数据库时,默认名称为 testdb
2spring.datasource.jndi-namestring数据源的JNDI名称
3spring.datasource.generate-unique-namestring是否随机生成一个数据源的名称默认为 false
4spring.datasource.usernamestring连接数据库的用户名
5spring.datasource.passwordstring连接数据库的密码
6spring.datasource.typestring数据源(连接池)的类型所谓类型,即数据源(连接池)的全限定类名,如:com.alibaba.druid.pool.DruidDataSource 。默认情况下,spring boot 会从classpath中自动探测
7spring.datasource.urlstringJDBC连接的URL
8spring.datasource.driver-class-namestringJDBC连接的驱动类名必须是驱动类的全限定名,如:com.mysql.cj.jdbc.Driver 。默认情况下,spring boot 会根据 url 自动探测一个合适的 jdbc 驱动
9spring.datasource.schemastring指定数据库模式名称schema 在不同数据库产品中的语义是不一样的,在mysql中,它就是一个database, 很多用户都可以操作它。在oracle中,schema是一个用户的数据库资源存储空间,仅属于该用户,在mssql中又不一样
10spring.datasource.schema-usernamestring数据库模式对应的用户名a. 在mysql中:此项无意义
b. 在oracle中,用户名与数据库schema名称保持一致
c. 在mssql中,代表某个schema下的用户名
d. 在postgresql中,与mssql一致
11spring.datasource.schema-passwordstring数据库模式下个用户的密码a. 在mysql中:此项无意义
b. 在oracle中,代表schema的密码
c. 在mssql中,代表某个schema下,某个用户的密码
d. 在postgresql中,与mssql一致
12spring.datasource.separatorstring初始化SQL脚本中,语句间的分隔符默认为 ;
13spring.datasource.sql-script-encodingstring初始化SQL脚本的编码
14spring.datasource.initialization-modestring数据源的初始化模式默认为 embedded, 模式名称列表如下:
1. always : 无论数据库是否已被初始化,每次应用程序启动都会执行初始化脚本
2. embedded : 仅在嵌入式数据库(如H2、HSQL等)被使用且数据库文件不存在时执行初始化操作。如果数据库文件已存在,则不进行任何初始化操作
3. never : 从不执行初始化操作。无论数据库是否已被初始化,应用程序启动时都不会执行任何初始化脚本
4. unrecognized : 未识别的模式。如果指定了一个无效的模式值,将抛出异常
15spring.datasource.datastring数据源的表数据初始化脚本如: classpath: config-init-data.sql
16spring.datasource.data-usernamestring执行初始化数据SQL脚本的用户名即执行上面这个data文件的数据库用户名
17spring.datasource.data-passwordstring执行初始化数据SQL脚本的密码即执行上面这个data文件的数据库密码
18spring.datasource.platformstring数据库平台(产品)名称默认为 all
支持的数据库平台有:all、h2、oracle、mysql、mssql、postgresql、derby
19spring.datasource.jmx-enabledbool是否开启JMX功能开启后,可通过 JConsole、VisualVM 工具查看数据源的内部状态
20spring.datasource.xa.propertiesstringXA数据源的扩展属性这只是一个扩展属性的前缀,属性的配置依然是key value 键值对的形式, 如username、password 等
21spring.datasource.xa.data-source-class-namestringXA数据源的驱类全限定名称
22spring.datasource.continue-on-errorbool初始化脚本执行错误时,是否继续执行默认为 false

1.5.2 Apache DBCP 数据源配置

序号属性名类型用途备注
1spring.datasource.dbcp2.default-auto-commitbool是否默认为自动提交默认为 false
2spring.datasource.dbcp2.default-read-onlybool是否默认为只读连接默认为 false
3spring.datasource.dbcp2.default-transaction-isolationint默认的隔离级别默认为 -1 ,代表未设置 ,有以下值可设置:
1. NONE(0): 不支持事务
2.READ_UNCOMMITTED(1): 读未提交。允许脏读、不可重复读和幻读
3.READ_COMMITTED(2): 读已提交。防止脏读,但是仍允许不可重复读和幻读
3.REPEATABLE_READ(4): 可重复读。防止脏读和不可重复读,但是仍允许幻读
4.SERIALIZABLE(8): 串行化。最高的隔离级别,防止脏读、不可重复读和幻

由于是int类型,因此,只能设置为括号中的数字,而不是常量串。这些常量串定义在 java.sql.Connection 中

注:通常情况下,数据源属性仅在创建连接工厂实例前有效,但这些以 default 头的属性例外,他们只是预设了 JDCBC 连接中部分特性的默认值,但这些特性是可以在运行期动态设置的,比如隔离级别。那些在连接工厂创建以后就不能再修改的属性,都是描述连接池自身特性的,而非描述 JDBC 连接的特性
4spring.datasource.dbcp2.default-query-timeout-secondsinteger默认的查询超时秒数
5spring.datasource.dbcp2.default-catalogstring默认连接的catalog多数关系型数据库均没有实现 catalog 这个概念
6spring.datasource.dbcp2.default-schemastring默认连接的schema对于mysql而言,schema 与 database 是等效的
对于oracle 和 postgresql, schema 在database层级之下
7spring.datasource.dbcp2.cache-statebool连接池中的连接是否缓存状态默认为 true
8spring.datasource.dbcp2.lifobool从连接池中获取连接的方式是否为后进先出默认为 true
LIFO: 即 Last In First Out, 向池中申请连接时,将优先选择最后归还到池中的连接
FIFO: 即 First In First Out, 与LIFO正好相反,申请连接时,它将按照连接入池的顺序来选择
9spring.datasource.dbcp2.initial-sizeint连池的初始连接数默认为 0
10spring.datasource.dbcp2.max-totalint最大连接数,指定连接池中同时可从数据库分配的最大活动连接数默认为 8
11spring.datasource.dbcp2.max-idleint最大空闲连接数,指定连接池中保持的最大空闲连接数默认为 8
12spring.datasource.dbcp2.min-idleint最小空闲连接数,指定连接池中保持的最小空闲连接数默认为 0
13spring.datasource.dbcp2.max-wait-millisint连接等待超时时间,指定在连接池耗尽时,再次请求连接的最大等待时间单位:毫秒,默认为 -1,表示无限等待
14spring.datasource.dbcp2.validation-querystring用于验证连接是否有效的SQL查询语句默认为 null
当校验 sql 为 null 时,连接的校验逻辑是执行 Connection.isValid(int) 这个标准的 jdbc 接口方法,而不是执行 SELECT 1 这个语句。isValid(int) 方法会由JDBC驱动程序自行检查连接的有效性,如果在指定的时间(单位:秒)内未获取结果,则该方法返回false, 反之则返回内部实际的检测结果
15spring.datasource.dbcp2.validation-query-timeout-secondsint执行连接有效性检查的超时时长(单位:秒)默认为 -1, 表示无限等待
16spring.datasource.dbcp2.test-on-createbool创建连接时,是否执行可用性验证查询语句默认为 false
17spring.datasource.dbcp2.test-on-borrowbool在借用连接时,是否执行连接的可用性验证查询语句默认为 true
18spring.datasource.dbcp2.test-on-returnbool在将连接返回给连接池时,是否执行连接的可用性验证查询语句默认为 false
19spring.datasource.dbcp2.pool-prepared-statementsbool是否启用预编译语句的缓存池功能默认为 false, 如果设置为 true,则会同时创建 PreparedStatements与 CallableStatements 语句的缓存池
20spring.datasource.dbcp2.max-open-prepared-statementsint预编译语句池可同时分配的最大语句数量默认为 -1,代表不受限制
这是一个性能优化参数,当预编译语句被执行时,连接池会从预编译语句池中获取一个可用的预编译语句。如果预编译语句池中没有可用的预编译语句,连接池会根据需要创建新的预编译语句。max-open-prepared-statements属性用于限制连接池中同时打开的预编译语句的最大数量。一旦达到这个限制,连接池将不再创建新的预编译语句,直到有预编译语句被释放回连接池。
通过设置一个合理的值,可避免过多的资源消耗。
21spring.datasource.dbcp2.time-between-eviction-runs-millislong间隔多久执行一次空闲连接和过期连接的检查默认为 -1,表示不执行检查任务。单位:毫秒
22spring.datasource.dbcp2.num-tests-per-eviction-runint单次空闲连接检查任务要测试的最大连接数默认为 3
23spring.datasource.dbcp2.min-evictable-idle-time-millislong将连接移出池外的最小空闲时间默认为 1800000,即30分钟
24spring.datasource.dbcp2.soft-min-evictable-idle-time-millislong将连接柔性移出池外的最小空闲时间默认为 -1,单位:毫秒
功能与 min-evictable-idle-time-millis 等效,但有一个附加条件,就是池中空闲的连接数至少有min-idle个时,才执行将连接移出池外的操作,另外,本参数的优先级高于 min-evictable-idle-time-millis
25spring.datasource.dbcp2.eviction-policy-class-namestring空闲连接移出池外的策略类名默认为 org.apache.commons.pool2.impl.DefaultEvictionPolicy
26spring.datasource.dbcp2.test-while-idlebool连接空闲期间是否测试它的可用性默认为 false
空闲期间,对连接进行测试,如果测试结果为连接无效,则会将其移出连接池
27spring.datasource.dbcp2.connection-factory-class-namestring创建连接的连接工厂类名默认为 org.apache.commons.dbcp2.DriverConnectionFactory
28spring.datasource.dbcp2.connection-init-sqlslist指定连接创建后,可立即执行的,且仅执行一次的SQL语句默认为 null
29spring.datasource.dbcp2.access-to-underlying-connection-allowedbool是否允许直接访问底层的 jdbc 连接默认为 false
30spring.datasource.dbcp2.max-conn-lifetime-millislong连接的最大存活时长,单位:毫秒默认为 -1, 表示不受限制
该参数容易与 max-idle 混淆,本参数指的是一个连接最大可以存活多久,是整体时长。而 max-idle 设置的是一个连接的最大空闲时长
31spring.datasource.dbcp2.log-expired-connectionsbool是否在日志中输出过期的连接默认为 true
32spring.datasource.dbcp2.jmx-namestring连接池的 jmx 名称
33spring.datasource.dbcp2.disconnection-sql-codesset设置判断连接已断开的状态码默认为 null
该参数仅在 fast-fail-validation 为 true 时才有意义。默认情况下,执行SQL时,发生 SQLExcetion,且SQL状态码为以下内容,将被认定为连接已失效(关闭):
• 57P01: 管理员关闭了连接
• 57P02: 数据库崩溃导致连接关闭
• 57P03: 当前连接不可用
• 01002: SQL94 断开连接错误
• JZ0C0: Sysbase 断开连接错误
• JZ0C1: Sysbase 断开连接错误
• 08*:其它以08开发的 SQL_STATE 状态码
34spring.datasource.dbcp2.jmx-namestring连接池的 jmx 名称
35spring.datasource.dbcp2.fast-fail-validationbool是否开启连接有效性检查的快速失败特性默认为 false
连接池有专门的 Evictor 组件来检查它是否可用。实现手段通常是调用 JDBC 的isValid(int) 方法或执行一个简单的查询SQL。如果一个连接被标记为是可用的,而在实际用它执行SQL时抛出了致命(Fatal)类SQLException时,就会使用 Evictor 组件来查验连接的可用性状态。
多数据情况下,出现 Fatal 类 SQLException 都意味着数据库服务器不可用,此时再去进行可用性验证其实是多余的。 所以便有了快速失败校验(fast-fail-validation)这个特性,当这个参数设置为 true 时,会根据 SQLException 中的状态码来决定是否连接不可用。如果是,则不再使用 Evictor 组件来进一步校验连接的可用性。
那么哪些状态码可被认定为连接不可用呢,见 disconnection-sql-codes 这个参数
36spring.datasource.dbcp2.remove-abandoned-on-borrowbool是否在向池中获取连接时触发作废连接清理操作默认为 false
如果该参数设置为 true, 则每次获取连接时,都将进行作废连接的清理工作(即将标记为 abandoned 的连接从池中删除),但移除折条件不只是连接被标识为 abandoned, 还需同时满足以下条件 :
• 标记为 abandoned 的连接时长超过 remove-abandoned-timeout 秒
• getNumIdle() < 2
• getNumActive() > getMaxTotal() - 3
37spring.datasource.dbcp2.remove-abandoned-timeoutstring被标记为作废的连接从池中删除的前的保持时长,单位:秒默认为 300 秒
38spring.datasource.dbcp2.remove-abandoned-on-maintenanceboolean是否在连接池的维护任务中执行作废连接清理操作默认为 false
即便该参数设置为 true,也未必生效,必须要在 time-between-eviction-runs-millis 参数设置为一个正数时才有效,因为只有这个参数设置为一个有效的值时,连接池的维护任务才会被激活
39spring.datasource.dbcp2.log-abandonedbool是否在日志中输出执行作废连接清除的代码运行时堆栈信息默认为 false

不同的版本,配置属性名称会存在少许差异,准确配置名称参见工程中的 org.apache.commons.dbcp2.BasicDataSource 类

另外,也建议直接去DBCP的官网查阅各参数的详细说明

继续更新中......

2. 如何从Spring源码中查看默认配置

从官方源码中查看配置是最准确的,操作步骤如下:

  1. 所有配置都集中在 spring-boot-autoconfiure.jar 包中

  2. 找到类名以 AutoConfiguration 结尾的,你所关注的那个组件自动装配类
    比如:你关注JdbcTemplate, 则先找到 JdbcTemplateAutoConfiguration 这个类(稍后会以这个类为例子,详细说明)

  3. 找到类名以 Configuration 结尾的,你所关注的那个组件配置类
    与第二步的差异是:类名后缀没有了Auto字符,比如 JdbcTemplateConfiguration,通常这个类会在 AutoConfiguration 类中以 @Import 的方式引入,这样它的装配逻辑就可以自动执行了。因此,熟悉了以后,可以直接跳过第2步。

  4. 找到 AutoConfiguration 在装配组件时,所使用到的相应的 Properties 类的方法
    这个 Properties 就是我们日常开发所配置的内容,即第1章节列出的内容。但这些属性在不同的组件中,所属的类名各不相同。比如数据源组件的属性叫 DataSourceProperties,Jdbc模板的属性叫 JdbcProperties。这些 Properties 类中的属性,就是我们的配置项,也是第1章节内容的出处。

简而言之,配置项最终位于各种 Properties 类中。AutoConfiguration、Configuration、Properties 共同构成了 spring boot 组件自动化装配的基础。AutoConfiguration 负责在 spring boot 环境中触发某类组件的自动装配,Configuration 负责完成具体的装配逻辑,而 Properties 则提供了在运行时,从外部加载组件属性的特性

下面以 JdbcTemplateAutoConfiguration 和 JdbcTemplateConfiguration 为例,详细说明。JdbcTemplateAutoConfiguration 的代码如下:

 
package org.springframework.boot.autoconfigure.jdbc;
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(JdbcProperties.class)
@Import({ JdbcTemplateConfiguration.class, NamedParameterJdbcTemplateConfiguration.class })
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
public class JdbcTemplateAutoConfiguration {
}

可见,JdbcTemplateAutoConfiguration 类 Import 了 JdbcTemplateConfiguration,而 JdbcTemplateConfiguration 才是 JdbcTemplate 组件真实的装配逻辑所在处。JdbcTemplateConfiguration 的源码如下:

 
package org.springframework.boot.autoconfigure.jdbc;
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(JdbcOperations.class)
class JdbcTemplateConfiguration {
@Bean
@Primary
JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) {
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
JdbcProperties.Template template = properties.getTemplate();
jdbcTemplate.setFetchSize(template.getFetchSize()); // 使用jdbcProperties的设置
jdbcTemplate.setMaxRows(template.getMaxRows()); // 使用jdbcProperties的设置
if (template.getQueryTimeout() != null) {
jdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());
}
return jdbcTemplate;
}
}

从上面可以看到,JdbcTemplate 组件的属性是从 JdbcProperties 中读取的。

进一步查看 JdbcTemplate 源码,会发现有一些属性在 JdbcProperties 中是没有的,比如 skipResultsProcessing 和 resultsMapCaseInsensitive。JdbcTemplate 的这些 properties 就不能通过第1章节的方式来设置了,需要我们写代码来完成。

上面基于 JdbcTemplate 的例子比较简单,多数第三方组件都可以通过这种方式来查看配置。但数据源是比较特殊的,它有一个统一的上层抽象类 DataSource, 和多个实现类。且从源码查看 property 配置的方式也不同。比如 DBCP2 这个数据源,并没有一个叫做 Dbcp2DataSourceProperty 的类来从外部加载 DBCP2 的属性,所有的数据源配置都在 DataSourceProperties 类中. 各个具体的数据源属性,由不同的 property 前缀来区分。DBCP2 单独的属性就配置在 spring.datasource.dbcp2.* 下。那么问题来了:应该从哪里查看 DBCP2 单独的属性配置名称呢。答案是 DBCP2 的 DataSource 实现类,即:org.apache.commons.dbcp2.BasicDataSource 类。查看其它数据源产品的配置属性方法也是如此,即:各个数据源单独的配置属性,就在这些数据源产品的 DataSource 实现类上。

下面是官方的 DataSourceConfiguration 源码中与 DBCP2 数据源装配相关的代码片段

 
package org.springframework.boot.autoconfigure.jdbc;
abstract class DataSourceConfiguration {
protected static <T> T createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) {
return (T) properties.initializeDataSourceBuilder().type(type).build();
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(org.apache.commons.dbcp2.BasicDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp2.BasicDataSource", matchIfMissing = true)
static class Dbcp2 {
@Bean
// 这一行表明:DBCP2 自身的属性就在 BasicDataSource 中
@ConfigurationProperties(prefix = "spring.datasource.dbcp2")
org.apache.commons.dbcp2.BasicDataSource dataSource(DataSourceProperties properties) {
return createDataSource(properties, org.apache.commons.dbcp2.BasicDataSource.class);
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot项目常见问题包括: 1. 如何处理异常?可以使用Spring Boot提供的异常处理机制来处理异常。可以通过在代码使用@ControllerAdvice注解来定义全局异常处理器,并使用@ExceptionHandler注解来处理具体的异常情况。 2. 如何导入Spring Boot项目依赖?可以通过在项目的pom.xml文件添加对相应依赖的配置来导入项目依赖。可以使用Spring Initializr来快速生成一个基于Spring Boot项目,并在生成的项目添加所需的依赖。 3. 如何使用Spring Boot启动器?可以使用Spring Boot启动器来简化项目的依赖管理。通过在项目的pom.xml文件添加对Spring Boot启动器的依赖,可以自动引入所需的依赖项,无需手动配置每个依赖的版本号。 4. 如何配置MyBatis?可以使用@MapperScan注解来指定需要扫描的Mapper接口,并在配置文件配置相应的数据库连接信息和MyBatis的相关配置项。 5. 如何启动Spring Boot应用程序?可以通过使用SpringApplication类的run()方法来启动Spring Boot应用程序。可以在主类使用@SpringBootApplication注解来标识一个Spring Boot应用程序的入口点,并在main()方法调用run()方法来启动应用程序。 6. 如何使用外部配置文件?可以在Spring Boot应用程序的配置文件配置不同的环境变量和属性。可以使用@Value注解来注入配置文件属性值,并使用@ConfigurationProperties注解来将配置文件属性绑定到Java对象上。 7. 如何使用Spring Boot的自动配置Spring Boot提供了自动配置的功能,可以根据应用程序所使用的依赖和配置来自动配置应用程序的各个组件。可以通过在应用程序的配置类上添加@EnableAutoConfiguration注解来启用自动配置功能。 综上所述,Spring Boot项目常见问题涵盖了异常处理、项目依赖导入、启动器使用、MyBatis配置、应用程序启动、外部配置文件使用和自动配置等方面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值