简介
在这篇文章中,我将向你展示配置Spring Boot应用程序属性文件的最佳方法。
这并不只是理论上的建议。我在开发RevoGain时应用了所有这些技巧,RevoGain是一个网络应用,它允许你计算你在使用Revolut交易股票、商品或加密货币时实现的收益。
Spring Boot应用程序属性文件
当Spring Boot出现时,它提出了一个非常聪明的想法,即把所有的配置聚集在一个application.properties 文件中。
你可以使用Java属性文件或YAML文件,但我总是选择属性文件格式,因为我没有一个比例尺来解决YAML的缩进问题。
Spring Boot应用程序属性--Web配置
下面是我用来配置Web层的设置列表。
## Web error page
server.error.whitelabel.enabled=false
## Web HTTPS settings
server.tomcat.remoteip.remote-ip-header=x-forwarded-for
server.tomcat.remoteip.protocol-header=x-forwarded-proto
### Web Gzip
server.compression.enabled=true
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css
## Web static resources versioning
spring.web.resources.chain.strategy.content.enabled=true
spring.web.resources.chain.strategy.content.paths=/js/**,/css/**
### Web caching
spring.web.resources.cache.cachecontrol.max-age=30d
server.error.whitelabel.enabled 属性禁用了默认的白标错误页,这样我们就可以定制一个针对应用程序的错误页。
下一步是要有一个错误处理程序,允许你为认证和非认证的用户定制错误页面。
@Controller
public class ApplicationErrorController
extends BaseController implements ErrorController {
@RequestMapping("/error")
public String handleError(
Model model,
HttpServletRequest request) {
Object statusCodeValue = request.getAttribute(
RequestDispatcher.ERROR_STATUS_CODE
);
String errorMessage = null;
String requestPath = (String) request.getAttribute
RequestDispatcher.ERROR_REQUEST_URI
);
if (statusCodeValue != null) {
int statusCode = Integer.parseInt(statusCodeValue.toString());
if (statusCode == HttpStatus.NOT_FOUND.value()) {
errorMessage = String.format(
"The [%s] request could not be found.",
requestPath
);
} else if (statusCode == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
Object exception = request.getAttribute(
RequestDispatcher.ERROR_EXCEPTION
);
if(exception instanceof Throwable) {
String errorCause = ExceptionUtils
.getRootCause(
(Throwable) exception
)
.getMessage();
errorMessage = String.format(
"The [%s] request could not be processed - %s",
requestPath,
errorCause
);
} else {
errorMessage = String.format(
"The [%s] request could not be processed.",
requestPath
);
}
} else {
HttpStatus status = HttpStatus.valueOf(statusCode);
errorMessage = String.format(
"The [%s] request failed with this status code: %s",
requestPath,
status
);
}
}
if(errorMessage != null) {
model.addAttribute("error", errorMessage);
}
LOGGER.error(errorMessage);
return UserContext.getCurrentUser() != null ?
"error-logged-in" :
"error";
}
}
error-logged-in.html 是为认证用户显示的Thymeleaf页面,而error.html 是为非认证用户显示的Thymeleaf页面。我使用两个错误页面的原因是,初始登陆页面和实际应用布局之间的布局,尤其是菜单有所不同。
server.tomcat.remoteip 设置用于在代理服务器后面运行Spring Boot应用程序时启用HTTPS,因为AWS上就是这样的。
server.tomcat.remoteip.remote-ip-header=x-forwarded-for
server.tomcat.remoteip.protocol-header=x-forwarded-proto
你应该只对你在互联网上提供的所有网站和Web应用程序使用HTTPS。不仅通信安全,而且谷歌也会提高你的网页的排名。
网络压缩设置用于为Spring Boot使用的底层Tomcat服务器启用使用GZIP的HTTP压缩。
server.compression.enabled=true
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css
资源版本设置允许你在修改JS和CSS资源以及重新部署应用程序时避免缓存问题。
spring.web.resources.chain.strategy.content.enabled=true
spring.web.resources.chain.strategy.content.paths=/js/**,/css/**
因此,有了网络资源版本管理,一个像这样的Thymeleaf链接。
<link rel="stylesheet" th:href=@{/css/main.css}/>
将会被渲染成这样。
<link rel="stylesheet" href=/css/main-894af16207c18178542fdc5f96f46a2b.css/>
894af16207c18178542fdc5f96f46a2b 的后缀是一个基于main.css 内容生成的哈希值。如果你改变了文件内容,哈希值也会随之改变,这意味着你将使旧的缓存条目失效,因为这个文件将在用户第一次访问这个页面时从服务器中获取。
cache.cachecontrol.max-age 的设置用于缓存30天的网络资源。
spring.web.resources.cache.cachecontrol.max-age=30d
由于我们使用的是资源版本管理,我们可以为我们的网络资源设置更长的缓存期,使页面渲染更快,因为需要从Webserver上获取的内容更少。
Spring Boot应用程序属性--数据库配置
数据访问层对应用程序的性能有最重要的影响。因此,注意我们如何配置它是非常重要的。
这是一个设置列表,如果你在Spring Boot应用程序中使用MySQL和HikariCP,你可以使用这些设置。
## DataSource properties
spring.datasource.url=jdbc:mysql://localhost:3306/revogain
spring.datasource.username=${REVOGAIN_DB_USER}
spring.datasource.password=${REVOGAIN_DB_PASSWORD}
## HikariCP configuration
spring.datasource.hikari.minimumIdle=0
spring.datasource.hikari.maximum-pool-size=40
spring.datasource.hikari.maxLifetime=900000
spring.datasource.hikari.transaction-isolation=TRANSACTION_READ_COMMITTED
spring.datasource.hikari.auto-commit=false
spring.datasource.hikari.data-source-properties.useServerPrepStmts=false
spring.datasource.hikari.data-source-properties.cachePrepStmts=true
spring.datasource.hikari.data-source-properties.prepStmtCacheSize=500
spring.datasource.hikari.data-source-properties.prepStmtCacheSqlLimit=1024
最小的连接池大小是0 ,它最多可以增长到40 连接。
spring.datasource.hikari.minimumIdle=0
spring.datasource.hikari.maximum-pool-size=40
spring.datasource.hikari.maxLifetime=600000
由于应用程序使用Aurora MySQL,连接管理与使用标准MySQL实例时有一点不同。正如[Aurora连接管理手册]中所解释的,Aurora MySQL使用一个工作线程池,可以从一个用户会话动态地切换到另一个用户会话。因此,连接池大小被设置为一个略低于Aurora实例类型所规定的连接限制的值(例如,db.t2.small 和db.t3.small 节点为45)。
spring.datasource.hikari.maxLifetime 的设置指示Hikari在10分钟后退出池中的连接。保持连接开放很长时间并不是一个好主意,因为连接可能因网络故障而意外关闭,而池子里的人并不知道。
默认隔离级别被设置为READ_COMMITTED ,以[优化MySQL在遍历集群索引进行批量更新或删除时持有的间隙锁的数量]。
auto-commit 模式被禁用,我们要让休眠通过 hibernate.connection.provider_disables_autocommit设置让Hibernate知道这一点。这样,Hibernate就可以在执行查询或刷新持久化上下文之前懒洋洋地获取数据库连接,而不是默认的行为,即让Hibernate在进入一个 @Transactional方法。
为了启用语句缓存,我们设置了以下属性。
spring.datasource.hikari.data-source-properties.useServerPrepStmts=false
spring.datasource.hikari.data-source-properties.cachePrepStmts=true
spring.datasource.hikari.data-source-properties.prepStmtCacheSize=500
spring.datasource.hikari.data-source-properties.prepStmtCacheSqlLimit=1024
Spring Boot应用程序属性 - Hibernate配置
这是一个设置列表,如果你使用Spring Data JPA,它在幕后使用Hibernate,你可以使用这个设置。
## Hibernate properties
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=false
spring.jpa.open-in-view=false
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
spring.jpa.properties.hibernate.jdbc.batch_size=15
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.connection.provider_disables_autocommit=true
spring.jpa.properties.hibernate.query.in_clause_parameter_padding=true
spring.jpa.properties.hibernate.query.fail_on_pagination_over_collection_fetch=true
spring.jpa.properties.hibernate.query.plan_cache_max_size=4096
logging.level.net.ttddyy.dsproxy.listener=debug
spring.jpa.hibernate.ddl-auto 设置为none ,以禁用hbm2ddl模式生成工具,因为我们使用Flyway来自动管理数据库模式。
spring.jpa.show-sql 被设置为false ,以避免Hibernate将SQL语句打印到控制台。正如我在这篇文章中解释的那样,最好使用datasource-proxy 来完成这项任务。而这就是为什么我们在开发模式中把logging.level.net.ttddyy.dsproxy.listener 属性设置为debug 。当然,在生产配置文件中,这个属性被设置为info 。
设置spring.jpa.open-in-view 属性是因为我们想禁用Spring Boot中默认启用的可怕的Open-Session in View(OSIV)。OSIV的反模式会导致严重的性能和扩展问题,所以最好在项目开发的一开始就禁用它。
spring.jpa.properties.hibernate.dialect 属性使用org.hibernate.dialect.MySQL57Dialect 值,因为这个应用程序使用的是 Aurora MySQL 5.7 版本。
spring.jpa.properties.hibernate.jdbc.time_zone 属性将默认时区设置为UTC ,以使其更容易处理跨多个时区的时间戳。
为了启用自动JDBC批处理,我们要设置以下三个属性。
spring.jpa.properties.hibernate.jdbc.batch_size=15
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
第一个属性将默认的批处理大小设置为15 ,这样就可以在一次数据库往返中分组并发送多达15组绑定参数值。接下来的两个设置是为了在使用级联时增加批处理的可能性。
spring.jpa.properties.hibernate.connection.provider_disables_autocommit 属性是指示Hibernate在打开数据库连接时,连接池禁用自动提交标志。
spring.jpa.properties.hibernate.query.in_clause_parameter_padding 设置增加了IN查询的语句缓存的可能性,因为它减少了在改变IN子句参数列表时可能产生的SQL语句的数量。
设置spring.jpa.properties.hibernate.query.fail_on_pagination_over_collection_fetch 属性是因为我们希望Hibernate在分页查询使用JOIN FETCH 指令时抛出一个异常。
设置
spring.jpa.properties.hibernate.query.plan_cache_max_size 属性是为了增加Hibernate查询计划缓存的大小。通过使用更大的缓存大小,我们可以减少JPQL和Criteria API查询编译的次数,从而提高应用性能
结论
配置Spring Boot应用程序属性文件是一项非常重要的任务,因为许多性能调整设置在默认情况下是不启用的。