问题描述
应用程序配置在现代 Java EE 应用程序中属于什么位置?人们有哪些最佳实践建议?
Where does application configuration belong in modern Java EE applications? What best practice(s) recommendations do people have?
通过应用程序配置,我指的是其他盒子上的服务的连接设置,包括外部(例如 Twitter 和我们的内部 Cassandra 服务器......用于诸如主机名、凭据、重试尝试之类的东西)以及那些与业务相关的设置逻辑(人们可能想在类中存储为常量的东西,例如某些东西到期的天数等).
By application configuration, I mean settings like connectivity settings to services on other boxes, including external ones (e.g. Twitter and our internal Cassandra servers...for things such as hostnames, credentials, retry attempts) as well as those relating business logic (things that one might be tempted to store as constants in classes, e.g. days for something to expire, etc).
假设:
- 我们正在使用单个 EAR 文件部署到 Java EE 7 服务器 (Wildfly 8.1),该文件包含多个 war 和一个 ejb-jar.
- 我们将部署到各种环境:单元测试、本地开发安装、基于云的 UAT 基础设施、压力测试和生产环境.我们的许多属性会因这些环境中的每一个而异.
- 如果这是人们推荐的最佳实践,我们不反对将属性配置耦合到 DI 框架.
- 所有这些都是为了新的开发,所以我们不必遵守旧的要求或限制.我们非常关注当前的现代最佳做法.
配置属于 EAR 内部还是外部?
Does configuration belong inside or outside of an EAR?
如果在 EAR 之外,在哪里以及如何最好地可靠地访问它们?
If outside of an EAR, where and how best to reliably access them?
如果 在 EAR 中,我们可以将它存储在类路径中的任何位置,以便在执行期间轻松访问.但是我们必须在每次配置更改时重新组装(并且可能重新构建).由于我们将有多个环境,我们需要一种方法来区分 EAR 中的文件.我在这里看到两个选项:
If inside of an EAR we can store it anywhere in the classpath to ease access during execution. But we'd have to re-assemble (and maybe re-build) with each configuration change. And since we'll have multiple environments, we'd need a means to differentiate the files within the EAR. I see two options here:
- 利用预期的文件名(例如
cassandra.properties
),然后构建多个特定于环境的 EAR(例如appxyz-PROD.ear
). - 构建一个 EAR(例如
appxyz.ear
)并将我们所有的各种环境配置文件放入其中,在每个配置文件名后附加一个环境变量(例如cassandra-PROD.属性
).当然,还要添加一个环境变量(到 vm 或其他地方),以便代码知道要提取哪个文件.
- Utilize expected file names (e.g.
cassandra.properties
) and then build multiple environment specific EARs (eg.appxyz-PROD.ear
). - Build one EAR (eg.
appxyz.ear
) and put all of our various environment configuration files inside it, appending an environment variable to each config file name (egcassandra-PROD.properties
). And of course adding an environment variable (to the vm or otherwise), so that the code will know which file to pickup.
人们可以推荐哪些最佳做法来解决这一常见挑战?
What are the best practices people can recommend for solving this common challenge?
谢谢.
推荐答案
我不知道什么是最佳实践,但这是我们所做的.
I don't know what is best practice, but here is what we do.
(但请注意,这仅适用于每台服务器的每个应用程序安装一个,并且当您想要使用每台服务器的多个部署时会失败,例如多租户部署).
(Note however that this only works well for one installation per application per server and will fail when one wants to use multiple deployments per server, say for multitenancy deployments).
我们使用一种有点复杂的 CDI 注入方法将 .properties
文件中的配置值直接注入到 bean 中,如下所示:
We use a somewhat sophisticated CDI injection approach to inject configuration values from .properties
files directly into beans, like this:
@Inject @ConfigurationValue(value="amazonS3FileContentsAccessKey")
private String accessKey;
相应的@Producer
bean 从类路径和给定的本地"位置读取配置文件:
The corresponding @Producer
bean reads configuration files from the class path and from a given "local" location:
- 每个 EAR 在类路径上包含一个全局"
.properties
文件,用于在环境中很少更改和/或通常保持一致的配置值(例如某些东西到期的天数).此外,全局配置文件包含合理的默认值(例如,数据库服务器主机名的localhost
").全局properties
文件(有多个,见下文)在源代码树中维护. - 对于每个开发环境/安装/服务器/部署,都有一个(可能)本地"属性文件,其中包含覆盖全局配置设置的本地设置,例如数据库名称、密码等.
- Each EAR contains a "global"
.properties
file on the class path for configuration values that change seldom and/or usually remain consistent through environments (such as days for something to expire). Further, the global configuration file contains sane default values (e.g. "localhost
" for database server hostname). The globalproperties
files (there are multiple, see below) are maintained in the source tree. - For every development environment/installation/server/deployment, there (possibly) is a "local" properties file that contains the local settings that overwrite the global configuration's settings, e.g., database names, passwords etc.
本地"属性文件的预期路径在全局配置文件(例如,/etc/myapp/local.properties
)或 C:myapplocal.properties 中配置
.
The expected path to "local" properties files is configured in the global configuration file (e.g., /etc/myapp/local.properties
) or C:myapplocal.properties
.
实际上,我们甚至允许将文件名中的某些变量替换为本地配置文件,例如${hostname}
".最初的想法是,本地属性也可以通过主机名(local.machineA.properties
、local.machineB.properties
)来区分,从而在一些中央源代码控制中进行维护,但我们目前不使用它,因为我们的生产设置在所有机器上都是相同的(Amazon S3 密钥、数据库密码/主机等).
Actually, we even allow substitution of some variables in the filename for the local configuration files, such as "${hostname}
". The original idea was that the local properties could also be maintained in some central source control by distinguishing them by hostname (local.machineA.properties
, local.machineB.properties
), but we don't use that at the moment, because our production settings are the same on all machines (Amazon S3 keys, database password/host etc).
我们根据使用 Maven 配置文件的开发阶段组装不同的 EAR.
在汇编时,所需的 global.${profile.name}.properties
文件(其中 profile.name
是,例如,dev
或 production
) 被复制到类路径中预期的 global.properties
文件中.
We assemble different EARs depending on the stage of development using Maven profiles.
On assemply, the desired global.${profile.name}.properties
file (where profile.name
is, e.g., dev
or production
) is copied to the expected global.properties
file in the classpath.
例如,dev
和 testing
共享一个公共的 AmazonS3 secret/bucket,在 configuration.dev.properties
中为所有开发人员配置一次code> 文件,而 configuration.production.properties
不包含我们的生产密钥.
For example, dev
and testing
share a common AmazonS3 secret/bucket, which is configured once for all developers in the configuration.dev.properties
file, while the configuration.production.properties
does not contain our production keys.
此外,我们的 dev
和 testing
环境已经启用并配置了调试,比如 web.xml
,当然还有 staging
和 production
没有.我们基于 .properties
的方法无法更改诸如 web.xml
之类的文件,但使用 Maven 构建配置文件很容易.
Furthermore, our dev
and testing
environments have debugging enabled and configured in, say web.xml
, but of course staging
and production
have not. Our .properties
-based approach cannot change files such as web.xml
, but with Maven build profiles it's easy.
这篇关于Java EE 7 属性文件配置的最佳实践建议是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!