Ratpack有非常有用的方法在我们的应用程序中应用应用程序配置。我们可以从不同格式的文件中读取配置属性,如JSON、YAML和Java属性,并且可以从不同的位置读取文件,如类路径或文件系统。我们还可以通过命令行上的Java系统属性来设置配置属性,或者使用环境变量。
我们使用ratpack.config.ConfigData
用静态of
方法向我们的应用程序添加配置属性。我们为of
方法来构建我们的配置。在这里,我们指定外部文件、位置和我们希望为应用程序包含的其他配置选项。如果在多个配置源中定义了相同的配置属性,Ratpack将应用最后发现的值。例如,通过这种方式,我们可以提供默认值,并且如果我们最后应用环境变量,允许它们被环境变量覆盖。
为了使用收集的值,我们使用get
的方法ConfigData
实例。我们可以将配置属性应用于配置类的属性,然后自动实例化该配置类。我们将它添加到注册表中,这样我们就可以在我们的应用程序中进一步使用配置属性。
在下面的Ratpack应用程序示例中,我们使用不同的方法来应用配置属性。它的灵感来自Spring Boot如何读取和应用外部化的配置属性。首先我们使用一个简单的Map
使用默认值,然后在类路径中扫描具有以下名称的文件application.yml
,application.json
和application.properties
在类路径的根目录或config
包裹。接下来,在相对于应用程序启动位置的文件系统上搜索相同的文件名。下一个Java系统属性从sample.
应用于配置。最后,环境变量从SAMPLE_
被解释为配置属性。
让我们从简单的配置类和属性开始,我们希望通过Ratpack的配置功能来设置:
// File: src/main/groovy/com/mrhaki/SampleConfig.groovy
package com.mrhaki
/**
* Configuration properties for our application.
*/
class SampleConfig {
/**
* URL for external service to invoke with HTTP client.
*/
String externalServiceUrl
/**
* URI to access the Mongo database.
*/
String mongoUri
/**
* Indicate if we need to use a HTTP proxy.
*/
boolean useProxy
/**
* Simple message
*/
String message
}
接下来我们有一个非常简单的Ratpack应用程序。这里我们使用ConfigData.of
有许多帮助器方法可以从不同的来源读入配置属性:
// File: src/ratpack/Ratpack.groovy
import com.google.common.io.Resources
import com.mrhaki.SampleConfig
import ratpack.config.ConfigData
import ratpack.config.ConfigDataBuilder
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import static groovy.json.JsonOutput.prettyPrint
import static groovy.json.JsonOutput.toJson
import static ratpack.groovy.Groovy.ratpack
ratpack {
bindings {
final ConfigData configData = ConfigData.of { builder ->
// Set default value, can be overridden by
// configuration further down the chain.
// The map must have String values.
builder.props(['app.useProxy': Boolean.TRUE.toString()])
loadExternalConfiguration(builder)
// Look for system properties starting with
// sample. to set or override configuration properties.
builder.sysProps('sample.')
// Look for environment variables starting
// with SAMPLE_ to set or override configuration properties.
builder.env('SAMPLE_')
builder.build()
}
// Assign all configuration properties from the /app node
// to the properties in the SampleConfig class.
bindInstance(SampleConfig, configData.get('/app', SampleConfig))
}
handlers {
get('configprops') { SampleConfig config ->
render(prettyPrint(toJson(config)))
}
}
}
private void loadExternalConfiguration(final ConfigDataBuilder configDataBuilder) {
final List<String> configurationLocations =
['application.yml',
'application.json',
'application.properties',
'config/application.yml',
'config/application.json',
'config/application.properties']
configurationLocations.each { configurationLocation ->
loadClasspathConfiguration(configDataBuilder, configurationLocation)
}
configurationLocations.each { configurationLocation ->
loadFileSystemConfiguration(configDataBuilder, configurationLocation)
}
}
private void loadClasspathConfiguration(
final ConfigDataBuilder configDataBuilder,
final String configurationName) {
try {
final URL configurationResource = Resources.getResource(configurationName)
switch (configurationName) {
case yaml():
configDataBuilder.yaml(configurationResource)
break
case json():
configDataBuilder.json(configurationResource)
break
case properties():
configDataBuilder.props(configurationResource)
break
default:
break
}
} catch (IllegalArgumentException ignore) {
// Configuration not found.
}
}
private void loadFileSystemConfiguration(
final ConfigDataBuilder configDataBuilder,
final String configurationFilename) {
final Path configurationPath = Paths.get(configurationFilename)
if (Files.exists(configurationPath)) {
switch (configurationFilename) {
case yaml():
configDataBuilder.yaml(configurationPath)
break
case json():
configDataBuilder.json(configurationPath)
break
case properties():
configDataBuilder.props(configurationPath)
break
default:
break
}
}
}
private def yaml() {
return hasExtension('yml')
}
private def json() {
return hasExtension('json')
}
private def properties() {
return hasExtension('properties')
}
private def hasExtension(final String extension) {
return { filename -> filename ==~ /.*\.${extension}$/ }
}
接下来,我们创建一些外部配置文件:
# File: src/ratpack/application.yml
---
app:
mongoUri: mongodb://mongo:27017/test
# File: src/ratpack/application.properties
app.externalServiceUrl = http://remote:9000/api
app.message = Ratpack rules!
让我们运行应用程序,并查看configprops
端点:
$ http localhost:5050/configprops
...
{
"externalServiceUrl": "http://remote:9000/api",
"useProxy": true,
"message": "Ratpack rules!",
"mongoUri": "mongodb://mongo:27017/test"
}
接下来,我们停止应用程序,用Java系统属性启动它-Dsample.app.useProxy=false
和环境变量SAMPLE_APP__MESSAGE='Ratpack rocks!'
。我们检查了configprops
再次结束:
$ http localhost:5050/configprops
...
{
"externalServiceUrl": "http://remote:9000/api",
"useProxy": false,
"message": "Ratpack rocks!",
"mongoUri": "mongodb://mongo:27017/test"
}
用Ratpack 1.0.0编写。
这是第1000篇博客帖子。我在博客上写了很多不同的主题,从Apache Cocoon、Netbeans开始,接着是Groovy和Groovy相关的技术,比如Grails、Gradle。也是关于其他开发者主题,比如Asciidoctor等等。我希望你喜欢第一个1000,因为我还没有完成,我会继续写更多关于伟大技术的博客。