15

我目前正在从事一个已经处于测试阶段的 j2ee 项目。现在,我们只是在解决部署过程中的一些问题。具体来说,战争中嵌入了许多文件(一些 xml 文件和 .properties),需要根据您是在开发、测试还是生产环境中部署不同的版本。诸如日志级别、连接池等的东西。

所以我想知道这里的开发人员如何构建他们部署 web 应用程序的过程。您是否将尽可能多的配置卸载到应用程序服务器?您是否在部署之前以编程方式替换设置文件?在构建过程中选择一个版本?手动编辑战争?

此外,您在通过应用程序服务器的静态库提供依赖项方面走了多远,您自己在战争中投入了多少?所有这些只是为了了解目前常见的(或者可能是最佳的)实践是什么。

4

5 回答 5

8

我认为如果属性是特定于机器/部署的,那么它们属于机器。如果我要在战争中结束一切,它应该是可放置的,这意味着它没有特定于运行它的机器。如果战争中有机器相关的属性,这个想法就会被打破。

我喜欢做的是用 properties.example 文件构建一个项目,每台机器都有一个 .properties,它位于战争可以访问的地方。

另一种方法是使用 ant 任务,例如 dev-war、stage-war、prod-war,并将项目的属性集包含在 war-build 中。我不太喜欢这样,因为作为项目构建的一部分,您最终将在单个服务器上拥有诸如文件位置之类的东西。

于 2009-02-24T15:50:40.567 回答
6

我在一个单独的服务器团队为我们的应用程序执行 QA 和生产服务器配置的环境中工作。每个应用程序通常部署在 QA 中的两台服务器和生产中的三台服务器上。我的开发团队发现,最好通过将尽可能多的配置放入战争(或耳朵)中来最大限度地减少服务器上所需的配置量。这使得服务器配置更容易,并且还最大限度地减少了服务器团队错误配置服务器的机会。

我们没有特定于机器的配置,但我们有特定于环境的配置(Dev、QA 和 Production)。我们将配置文件存储在按环境命名的 war 文件中(例如 dev.properties、qa.properties、prod.properties)。我们在服务器 VM 的 java 命令行上放置了一个 -D 属性来指定环境(例如 java -Dapp.env=prod ...)。应用程序可以查找 app.env 系统属性并使用它来确定要使用的属性文件的名称。

我想如果您有少量特定于机器的属性,那么您也可以将它们指定为 -D 属性。Commons Configuration 提供了一种将属性文件与系统属性结合起来的简单方法。

我们在服务器上配置连接池。我们为每个环境命名相同的连接池,并将分配给每个环境的服务器指向适当的数据库。应用程序只需要知道一个连接池名称。

于 2009-02-25T03:19:58.350 回答
4

wrt 配置文件,我认为史蒂夫的答案是迄今为止最好的答案。我会添加使外部文件相对于 war 文件的安装路径的建议 - 这样您就可以在具有不同配置的一台服务器上安装多个 war。

例如,如果我dev.war的解压到/opt/tomcat/webapps/dev.,那么我将使用ServletContext.getRealPath来查找基本文件夹和 war 文件夹名称,因此配置文件将../../config/dev相对于 war 或/opt/tomcat/config/dev绝对存在。

我也同意Bill关于尽可能少地放入这些外部配置文件的观点。根据您的环境使用数据库或 JMX 来存储尽可能多的数据。Apache Commons Configuration 有一个很好的对象来处理由数据库表支持的配置。

关于库,我同意unknown将所有库都放在WEB-INF/libwar 文件(自打包)的文件夹中。优点是应用程序的每次安装都是自主的,并且您可能同时使用不同版本的库来构建不同的战争。

缺点是它将使用更多内存,因为每个 Web 应用程序都有自己的类副本,由其自己的类加载器加载。

如果这引起了真正的担忧,那么您可以将 jar 放在您的 servlet 容器($CATALINA_HOME/lib用于 tomcat)的公共库文件夹中。但是,在同一台服务器上运行的所有 Web 应用程序安装都必须使用相同版本的库。(实际上,这并不完全正确,因为您可以在必要时将覆盖版本放在单个WEB-INF/lib文件夹中,但是维护起来非常麻烦。)

在这种情况下,我将为公共库构建一个自动安装程序,使用 InstallShield 或NSIS或等效于您的操作系统。可以轻松判断您是否拥有最新的库集,以及升级、降级等。

于 2009-02-25T04:34:47.750 回答
2

我通常制作两个属性文件:

  • 一个用于嵌入在应用程序中的应用程序细节(消息、内部“神奇”词),
  • 另一个用于环境细节(数据库访问、日志级别和路径......)在每个服务器的类路径上公开并“粘贴”(未随我的应用程序提供)。通常我“mavenise”或“anttise”这些以放置特定值,具体取决于目标环境。
  • 很酷的家伙使用 JMX 来维护他们的应用程序配置(配置可以实时修改,无需重新部署),但它对我的需求来说太复杂了。

服务器(静态?)库:我强烈反对在我的应用程序中使用服务器库,因为它增加了对服务器的依赖:

  1. IMO,我的应用程序必须是“自打包的”:放弃我的战争,仅此而已。我见过有 20 Mbs 罐子的战争,这对我来说并不令人不安。
  2. 一个常见的最佳实践是将您的外部依赖限制在 J2EE 教条所提供的范围内:J2EE API(使用 Servlet、Ejbs、Jndi、JMX、JMS...)。您的应用程序必须是“与服务器无关的”。
  3. 将依赖项放入您的应用程序(war、ear、wathever)是自我记录:您知道您的应用程序依赖于哪些库。使用服务器库,您必须清楚地记录这些依赖关系,因为它们不太明显(很快您的开发人员就会忘记这个小魔法)。
  4. 如果您升级您的应用服务器,您所依赖的服务器库也可能会发生变化。AppServer 编辑器不应该在其内部库上保持版本与版本之间的兼容性(而且大多数时候,他们不会)。
  5. 如果您使用嵌入在您的 appServer 中的广泛使用的库(想到 jakarta commons logging,又名 jcl)并且想要升级它的版本以获得最新功能,您将承担 appServer 不支持它的巨大风险。
  6. 如果您依赖于静态服务器对象(在服务器类的静态字段中,例如 Map 或日志),则必须重新启动应用服务器以清除此对象。您失去了热重新部署应用程序的能力(旧的服务器对象在重新部署之间仍然存在)。使用 appServer 范围的对象(J2EE 定义的对象除外)可能会导致细微的错误,特别是如果该对象在多个应用程序之间共享时。这就是为什么我强烈反对使用驻留在 appServer 库的静态字段中的对象。

如果您绝对需要“此应用程序服务器的 jar 中的此对象”,请尝试将 jar 复制到您的应用程序中,希望不依赖其他服务器的 jar,并检查您的应用程序的类加载策略(我习惯将“父级”放在最后一个类加载我所有应用程序的政策:我确信我不会被服务器的罐子“污染” - 但我不知道这是否是“最佳实践”)。

于 2009-02-25T02:28:47.053 回答
0

我将所有配置都放入数据库中。容器(Tomcat、WebSphere 等)让我可以访问初始数据库连接,从那时起,一切都来自数据库。这允许多个环境、集群和动态更改而无需停机(或至少无需重新部署)。特别好的是能够动态更改日志级别(尽管您需要管理屏幕或后台刷新来获取更改)。显然,这仅适用于启动应用程序不需要的东西,但通常,您可以在启动后很快进入数据库。

于 2009-02-24T18:55:22.773 回答