是否有任何模式或最佳实践可用于简化跨多个环境更改Java Web应用程序的配置配置文件。例如JDBC URL,SOAP端点等。
作为帮助澄清我的问题的一些背景知识,我使用了几个大型的Java Web应用程序,这些应用程序在任何给定的发布周期中都可以通过6个不同的环境;开发,集成,QA,性能并最终部署到多个生产服务器。在每个环境中,配置都需要更改。目前,每个部署的大多数配置更改都是手动完成的,既费时又容易出错 有没有办法从这个过程中进行人工干预?
答案 0 :(得分:31)
我很惊讶没有人引用Jakarta Commons Configuration API(http://commons.apache.org/configuration/)来回答这个问题。它允许您拥有文件层次结构(或其他配置源,如XML,JNDI,JDBC等)。这就是Jeremy Seghi所说的,它为你提供了一个很好的方法来同时拥有默认值和本地覆盖。
最好的部分是它是经过测试的工作解决方案,因此您不必亲自制作一些东西。
答案 1 :(得分:15)
我最近倾向于使用.NET,所以我的Java相当生疏。我很确定这可以用任何语言进行一些调整。
我们使用.NET配置系统的扩展,允许我们将环境和/或应用程序特定设置与更全局的配置结合使用。配置系统使用全局设置,每台计算机将其标识为开发,测试或生产(默认)。按顺序加载的一组文件,最后一个文件中的设置将覆盖先前加载的文件中定义的任何设置。文件按以下顺序加载:
所有文件都在源代码管理中,并且由于在应用程序运行的机器上定义了环境;因为它不会访问“beta”配置,除非机器配置将其标识为“beta”,我们可以提升所有配置文件,而不必担心无意中将我们的生产应用程序指向开发数据库。
答案 2 :(得分:11)
以下是我使用或遇到过的一些可行做法。在实践中通常需要将这些结合起来。
在构建
时替换配额中的变量值这是一个如何使用Apache Ant完成此操作的示例。可以使用构建配置文件控制Ant属性(${var.name}
):
<filterset id="variables.to.replace">
<filter token="APPNAME" value="${app.name}"/>
<filter token="WEBAPP-PATH" value="${webapp.path}"/>
<filter token="ENCRYPT-ALGORITHM" value="${encrypt.algorithm}"/>
<filter token="ERROR-MAILTO" value="${error.mailTo}"/>
<!--...-->
</filterset>
<!-- Then, when building & copying the conf, replace the variables: -->
<copy todir="${properties.target.dir}">
<!-- env specific conf files -->
<fileset dir="${basedir}/env/${run.env}/webapp/WEB-INF/classes" />
<filterset refid="variables.to.replace"/>
</copy>
好处是你可以在构建时很好地控制不同的配置。糟糕的是,如果将这种方法广泛用于大量不同的配置,系统往往会变得非常复杂并且难以维护。此外,必须构建配置也意味着更慢的开发周期。
在webapp启动时替换战争中的conf变量
这就是我在使用Spring Framework时通常所做的事情,即使只有一个可能的配置,也可以获得关注点分离的好处。使用Spring,您可以在webapp启动时在Spring上下文中使用PlaceholderPropertyConfigurer替换conf值。在这种情况下,您必须选择正确的配置,例如可以在构建时配置。
与替换构建时间相比,如果需要,可以更轻松地临时操作未压缩的Web应用程序中的值。当然,如果您更改任何内容,则需要重新启动Web应用程序,并且手动更改将不会在Web应用程序重新部署中持续存在。 Spring也仅限于Spring上下文,因此this doesnt' work e.g. in web.xml(但由于其局限性,可能应该避免在web.xml中使用变量)。
从预定义文件中读取本地conf
这种方法可能是最容易设置的方法:只需创建一个配置文件路径,例如: $HOME/mywebapp/conf.properties
并让您的网络应用程序在启动时以某种方式阅读。
这里的好处是你在构建/部署webapp时不必关心conf。无论如何,你应该有一些合理的conf默认值,然后可以被本地conf覆盖。
将conf置于数据库中
这是覆盖conf参数的最灵活的解决方案,但在某些情况下也会变得复杂。将conf置于包含name
和value
列的表中应该适用于大多数情况。
当然,您无法在数据库表中配置JDBC连接URL,但这对于简单的文本/数字配置是一个很好的解决方案,它会在设置数据库连接后影响webapp的操作。为了避免性能损失,请确保以某种方式缓存conf,如果它经常被访问。
额外做法
正如kgiannakakis所指出的,它还有助于为您的应用设置某种配置诊断页面。
答案 3 :(得分:6)
这很大程度上取决于Web应用程序服务器为您提供的选项。我们有多个具有不同JDBC URL的JBoss环境,所有服务器上的JNDI名称保持不变,只是本地实例上的配置发生了变化,因此从构建到构建没有任何问题。
我想简短的回答是,最佳做法是外部化配置并使用每个服务器的正确设置保留一个好的文件,并让Web应用程序读取该配置。外化和读取的确切性质取决于具体的配置和应用程序服务器。
编辑:这些配置不是作为战争的一部分(在我们的案例中是耳朵),不会被覆盖。
答案 4 :(得分:2)
首先,在一个地方经常更改所有配置设置。如果您需要同时设置JNDI,编辑数据库值和修改属性文件,这是非常困难的,以便完成配置。首选最容易编辑的媒体,也更容易验证所有内容是否设置正确。我会说属性文件是最好的解决方案。您可以轻松地编辑它们,只需要快速查看它们就可以看到一切正常。如果您选择属性文件,请仔细选择它们的标准位置,并为路径分配环境变量。
如果您有一个简单的测试可以验证所有设置是否正确,这也会有所帮助。例如,您可以拥有一个显示配置参数的测试页,并执行一些基本测试,例如尝试连接数据库或远程服务器。
答案 5 :(得分:1)
你想要的好例子是Seam或Grails(从Rails借用)。默认情况下有三个配置文件:prod,dev,test,但如果需要,可以定义更多。
在Seam项目中,构建由Ant文件完成。内容可以变化的Eeach文件是为每个配置文件定义的,例如数据源,sql脚本或属性文件。
import-dev.sql
import-prod.sql
import-test.sql
使用选择的配置文件运行ant文件时,将获取相应的文件,并从该文件名中截断配置文件名称。
以下是您可以放置在目标中的代码段
<copy tofile="${war.dir}/WEB-INF/classes/import.sql"
file="${basedir}/resources/import-${profile}.sql"/>
JDBC url,驱动程序名称可以外部化为属性文件(当然,配置文件名称为后缀)
<filterset id="persistence">
<filter token="transactionManagerLookupClass" value="${transactionManagerLookupClass}"/>
<copy tofile="${war.dir}/WEB-INF/classes/META-INF/persistence.xml"
file="${basedir}/resources/META-INF/persistence-${profile}.xml">
<filterset refid="persistence"/>
</copy>
或者您可以从命令行传递给ant构建调用的属性值。这是Seam完成的简短示例。
另一种选择是使用Maven。以maven方式由属性和profiles完成,但您也可以使用单独的模块来拆分配置并创建具有主要功能的其他模块。 maven属性和配置文件的典型用例示例是针对多个数据库,部署服务器等的运行配置。当您想要为不同供应商创建配置时更难,但对于Maven来说这不是问题:)
使用maven个人资料的好例子是此帖子Carlos Sanchez blog。
总结一下,我强烈建议查找Ant / Seam Maven参数化(配置文件)。这些解决方案还有另一个优点:可以在CI服务器中运行ant或maven脚本(如Hudson),并同时运行/测试所有配置文件。
答案 6 :(得分:1)
答案 7 :(得分:0)
有几种方法可以解决这个问题:
像你一样使用属性文件,但添加一个“元属性”文件,用于通过在属性文件名上定义环境值(例如localhost hostname)之间的映射来选择所使用的属性文件负荷。
将您的属性放入数据库,并将应用程序服务器中属性表的数据库连接定义为您的Web应用程序选择的资源。
不要将属性文件放在.war或.ear中,而是创建包含每个目标主机的属性文件的properties-deployhost.jar存档。将适当的.jar文件绑定到已部署的Web应用程序,方法是将其添加到类路径中(例如,通过每个Web应用程序的应用程序服务器配置中的共享库)。
在重新命名目标系统时,只需要在部署时不需要额外的手动步骤,而不必更新配置源并构建新的部署文件。
我确信这些和你的方法有很多变化,最好的选择取决于你的情况。
答案 8 :(得分:0)
我们的工作做得很好。
启动时,我们的程序读取硬编码路径中的配置文件。让我们说是:
/config/fun_prog/config.xml
每个程序都有一个不同的硬编码路径(FunProgram在fun_prog中,Super Server在sup_serv中,无论如何),所以我们不必担心它们相互走过。
XML文件由我们创建的一个小配置库读取。 XML文件包含数据库连接信息,通常是邮件服务器配置数据,发送通知的电子邮件地址,是否应该以测试模式运行,外部服务的URL等等。
因此,当我们需要进行更改时,我们会复制配置文件,编辑我们想要的内容,然后重新启动程序。由于我们有一个标准的服务器设置,任何程序都可以通过复制这些文件(以及必要的httpd.conf修改)部署在任何服务器上。
这不是很花哨,但效果很好。理解起来非常简单,添加新配置选项,备份和编辑。适用于所有平台(unix很明显,Windows会将以/开头的路径转换为c:\所以它的工作原理也没有编辑)。
我们的工作站基本上运行与服务器相同的软件,只需对该配置文件进行一些更改。
答案 9 :(得分:0)
请查看以下网址:http://issues.apache.org/jira/browse/CONFIGURATION-394
我们正在寻找的配置框架是Apache Commons Configuration之上的东西,必须支持并发问题,JMX问题和大多数商店(例如.properties文件,.xml文件或PreferencesAPI)。
weblogic团队在“管理控制台”上提供的内容是,通过它可以对配置进行事务性(原子)更新,以便通知已注册的侦听器。
Apache家伙坚持认为这个项目超出了Commons Configuration的范围,可能!
我附上了一个简单的配置框架,请看看。