如何在java webapps中管理嵌入式配置文件和库?

时间:2009-02-24 15:44:53

标签: java deployment java-ee web-applications war

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

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

您还可以通过应用程序服务器的静态库在多大程度上提供依赖关系,以及您自己投入了多少战争?所有这些只是为了了解目前常见(或可能是最佳)实践的一些想法。

5 个答案:

答案 0 :(得分:8)

我认为如果属性是特定于机器/部署的,那么它们就属于机器。如果我要在战争中把事情包起来,它应该是无法实现的,这意味着没有任何特定于它正在运行的机器。如果战争中有与机器有关的属性,这个想法就会破裂。

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

另一种方法是拥有ant任务,例如对于开发战争,阶段战争,生产战争以及在战争构建中融入项目的一系列属性。我不喜欢这个,因为你最终会在单个服务器上将文件位置等内容作为项目构建的一部分。

答案 1 :(得分:6)

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

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

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

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

答案 2 :(得分:4)

配置文件,我认为Steve's答案是迄今为止最好的。我会添加关于使外部文件相对于war文件的安装路径的建议 - 这样你就可以在具有不同配置的一台服务器中安装多次war。

e.g。如果我的dev.war被解压缩到/opt/tomcat/webapps/dev,那么我会使用ServletContext.getRealPath来查找基本文件夹和war文件夹名称,这样配置文件就会生成../../config/dev相对于/opt/tomcat/config/dev战争,或绝对的WEB-INF/lib

我同意Bill关于尽可能少地放在这些外部配置文件中。根据您的环境使用数据库或JMX来存储尽可能多的内容。 Apache Commons Configuration具有nice object,用于处理由数据库表支持的配置。

关于库,我同意unknown将所有库放在war文件的$CATALINA_HOME/lib文件夹中(自行打包)。优点是应用程序的每次安装都是自治的,并且您可能会同时使用不同版本的库来使用不同版本的战争。

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

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

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

答案 3 :(得分:2)

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

  • 一个用于应用程序中嵌入的应用程序细节(消息,内部“魔术”单词),
  • 另一个用于在每个服务器的类路径上暴露的环境细节(数据库访问,日志级别和路径......)和“粘贴”(不随我的应用程序提供)。通常我会根据目标环境“使用”或“反对”这些来设置特定值。
  • 酷人使用JMX维护他们的应用程序配置(可以实时修改,无需重新部署),但它太复杂,不能满足我的需求。

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

  1. IMO,我的应用程序必须“自行打包”:放弃我的战争,就是这样。我已经看到了装有20 Mbs罐子的战争,这对我来说并不令人不安。
  2. 一个常见的最佳实践是将外部依赖性限制为J2EE教条提供的内容:J2EE API(使用Servlets,Ejbs,Jndi,JMX,JMS ......)。您的应用必须是“服务器无关”。
  3. 在您的应用中添加依赖项(war,ear,wathever)是自我记录的:您知道应用依赖的库。使用服务器库时,您必须清楚地记录这些依赖关系,因为它们不太明显(很快您的开发人员就会忘记这个小小的魔力)。
  4. 如果升级您的appserver,您所依赖的服务器库的可能性也会发生变化。 AppServer编辑器不应该在版本之间保持内部库的兼容性(大多数情况下,它们不会)。
  5. 如果您使用广泛使用的appServer中嵌入的lib(jakarta commons logging,又名jcl,并且想到了ugrade它的版本以获得最新功能),那么您将承担appServer不支持的巨大风险它。
  6. 如果您依赖静态服务器对象(在服务器类的静态字段中,例如Map或日志),则必须重新启动应用程序服务器以清除此对象。您失去了热重新部署应用程序的能力(旧服务器对象在重新部署之间仍然存在)。使用appServer范围的对象(除了J2EE定义的对象)可能会导致细微的错误,尤其是在多个应用程序之间共享此对象时。这就是为什么我强烈反对使用驻留在appServer lib的静态字段中的对象。
  7. 如果您绝对需要“此appserver的jar中的此对象”,请尝试在您的应用程序中复制jar,希望不依赖于其他服务器的jar,并检查应用程序的类加载策略(我习惯于放置“父级”最后一个“我所有应用程序上的类加载策略:我确信我不会被服务器的jar”污染“ - 但我不知道它是否是”最佳实践“。)

答案 4 :(得分:0)

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