在Scala中设置项目的好方法是什么,它根据环境使用不同的配置。
我需要为开发,测试和生产环境专门设置不同的数据库(类似于Rails中的操作)
答案 0 :(得分:42)
我正在使用的另一个策略是使用includes。
我通常将我的DEV设置存储在default application.conf
文件中,然后我为其他环境创建一个新的conf文件,并包含默认文件。
假设我的DEV conf application.conf
看起来像这样:
myapp {
server-address = "localhost"
server-port = 9000
some-other-setting = "cool !"
}
然后对于PROD,我可以有另一个名为prod.conf
的文件:
include "application"
# override default (DEV) settings
myapp {
server-address = ${PROD_SERVER_HOSTNAME}
server-port = ${PROD_SERVER_PORT}
}
请注意,我仅覆盖 在PROD环境中更改的设置(some-other-setting
因此与DEV中相同)。
配置引导程序代码不会测试任何内容
...
val conf = ConfigFactory.load()
...
要从DEV切换到PROD conf,只需传递一个带有配置文件名称的系统属性即可:
java -Dconfig.resource=prod.conf ...
在DEV中,由于default将加载application.conf
,因此无需传递。
所以我们在这里使用Typesafe Config的默认加载机制来实现这一点。
我创建了一个简单的project来演示这种技术。随意克隆和实验。
答案 1 :(得分:20)
使用typesafe配置。像这样创建一个Config对象:
import com.typesafe.config._
object Config {
val env = if (System.getenv("SCALA_ENV") == null) "development" else System.getenv("SCALA_ENV")
val conf = ConfigFactory.load()
def apply() = conf.getConfig(env)
}
然后在application.conf
文件夹中创建src/main/resources
文件:
development {
your_app {
databaseUrl = "jdbc:mysql://localhost:3306/dev_db"
databaseUser = "xxxx"
databasePassword = "xxxx"
}
}
test {
your_app {
databaseUrl = "jdbc:mysql://localhost:3306/test_db"
databaseUser = "xxxxx"
databasePassword = "xxxx"
}
}
现在,您可以从应用程序的任何位置访问配置:
配置()。的getString( “your_app.databaseUrl”)
如果您在运行应用程序时设置了环境(例如export SCALA_ENV=test
),它将考虑正确的配置部分。默认为开发
答案 2 :(得分:2)
我对Daniel Cukiers解决方案不允许默认和覆盖的方式感到不满意,所以我改变它以充分利用它们。
您需要做的唯一配置是在系统上设置一个ENVIRONMENT变量(如果没有设置,则默认为'dev')
(Java解决方案,与Scala兼容):
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
public class MyCompanyConfig {
public final static Config base = ConfigFactory.load().getConfig("mycompany");
public final static String environment = System.getenv("ENVIRONMENT") == null ? "dev" : System.getenv("ENVIRONMENT");
/**
* Returns a subtree of the base configuration with environment settings applied.
*
* @param setting The subtree to return config for.
* @return A config with base in given setting, with environment modifications applied.
*/
public static Config load(String setting) {
Config config = base.getConfig(setting);
if (config.hasPath(environment)) {
return config.getConfig(environment).withFallback(config);
}
return config;
}
}
这允许库中的单个reference.conf看起来像这样:
mycompany.module1 {
setting1 : "adefaultvalue"
url : "localhost"
test {
// will be used where ENVIRONMENT="test"
url : "test.mycompany.com"
}
prod {
// will be used where ENVIRONMENT="prod"
setting1 : "changethedefault"
url : "www.mycompany.com"
}
}
用法:
Config conf = MyCompanyConfig.load("module1")
答案 3 :(得分:0)
这是Scala中的解决方案,允许覆盖,并且不依赖于外部库。
object Config {
var test: Map[String, String] = {
Map(
"libsvmData" -> new java.io.File("./src/test/resources/sample_libsvm_data.txt").getCanonicalPath,
"somethingElse" -> "hi"
)
}
var production: Map[String, String] = {
Map(
"libsvmData" -> "s3a://my-cool-bucket/fun-data/libsvm.txt",
"somethingElse" -> "whatever"
)
}
var environment = sys.env.getOrElse("PROJECT_ENV", "production")
def get(key: String): String = {
if (environment == "test") {
test(key)
} else {
production(key)
}
}
}
如果PROJECT_ENV
设置为test
,Config.get("somethingElse")
将返回"hi"
。否则,它将返回"whatever"
。
运行PROJECT_ENV=test sbt test
将变得很快,因此您可以让SBT在运行测试套件时设置环境变量。
fork in Test := true
envVars in Test := Map("PROJECT_ENV" -> "test")
以下是如何覆盖现有配置。
Config.test = Config.test ++ Map("somethingElse" -> "give me clean air")
我在a link to the full blog post写了这个话题。