我可以在多个环境中使用单个war文件吗?我是不是该?

时间:2009-10-28 00:13:38

标签: java jsp java-ee

我的工作中有一个Java Web应用程序,我想简化我们部署到DEV,QA和PROD环境的方式。

应用程序在启动时读取一系列属性,dev,qa和prod的属性文件不同。每当我想部署到某个环境时,我都会将特定于环境的属性文件放到我的app文件夹中,构建war,然后将其部署到三个tomcat 5.5服务器之一。

我想要做的是必须有一个.war,它具有所有环境的属性,并让应用程序在初始化过程中询问Web服务器,以确定应用程序所处的环境,从而确定哪些属性载入。是否有一种简单的方法(或者,这是一种标准的方式)?

8 个答案:

答案 0 :(得分:17)

这实际上取决于您使用这些属性的内容。

可以在容器本身(Tomcat 5.5. JNDI Resources中配置一些(例如数据源),也可以参见JDBC sources部分。)

其他(特定于应用程序)可能确实需要属性。在这种情况下,您的选择是:

  1. 在WAR文件中捆绑属性并根据某些外部交换机(环境变量或JVM属性)加载适当的子集
  2. 在解压为war的每台服务器上设置部署过程,并将属性文件(位于该服务器上的预定义位置,特定于该服务器)复制到WEB-INF/classes(或其他适当位置)
  3. 就“这是一个理想的目标”而言 - 是的,我想是的。在QA /分期中测试单个WAR然后部署到生产中会减少中间步骤,从而减少出错的机会。

    更新(根据评论):

    上面的项目#1指的是一个实际的环境变量(例如,您通过Windows中的SET ENV_NAME=QA或Linux中的ENV_NAME=QA; export ENV_NAME设置的内容。您可以使用System.getenv()从代码中读取其值并加载相应的属性文件:

    String targetEnvironment = System.getenv("TARGET_ENV");
    String resourceFileName = "/WEB-INF/configuration-" + targetEnvironment + ".properties";
    InputStream is = getServletContext().getResourceAsStream(resourceFileName);
    Properties configuration = new Properties();
    configuration.load(is);
    

    但是,您可以改为通过JNDI(see Environment Entries in Tomcat doc)定义标量值:

    <Context ...>
      <Environment name="TARGET_ENV" value="DEV" type="java.lang.String" override="false"/>
    </Context>
    

    并通过

    在您的应用中阅读
    Context context = (Context) InitialContext().lookup("java:comp/env");
    String targetEnvironment = (String) context.lookup("TARGET_ENV");
    // the rest is the same as above
    

    问题是,如果您仍将使用JNDI,您可以放弃您的属性文件并通过JNDI配置所有内容。您可以使用您的数据源作为实际资源,基本属性仍然是标量(尽管它们是类型安全的)。

    最终由您来决定哪种方式更适合您的特定需求;两者都有利有弊。

答案 1 :(得分:6)

你所做的是一场等待发生的事故......有一天,DEV战争将最终进入de PROD服务器,并且某些法律优于所有自然法则,这些问题将在凌晨2点被发现。无法解释为什么会这样,但有一天会发生。因此,我认为一场战争肯定是一个好主意。

您可以在相应的JVM中设置系统属性(-Dcom.yourdomain.configpath = / where / you / store / configfiles)并使用

获取此属性
String value = System.getProperty("com.yourdomain.configpath", "defaultvalue_if_any"); 

默认值可能指向战争中的某个位置(WEB-INF / ...),或者如果没有默认值,则用于在加载期间发出一些记录噪声以警告错误配置)。还要注意,这种技术不依赖于平台,所以你的dev机器可以是Windows机器和服务器的Linux机器,它可以应付这两者。我们通常在这个configpath中为每个应用程序创建一个子目录,因为有几个应用程序在服务器上使用这个系统,我们希望保持整洁。

作为额外的好处,您不会冒这种方式在PROD服务器上手动调整属性文件的风险。只是不要忘记在备份方案中包含文件存储的路径。

答案 2 :(得分:4)

我认为单个war文件是一个很好的方法,因为很高兴有信心你在DEV中测试的二进制文件与Production中的完全相同。我们这样做的方式,我们将配置保存在战争之外的单独属性文件中,但是在app服务器的类路径中。

如果你想保留战争中的所有属性(这确实使部署更容易,因为那时你不必也部署属性文件),你可以在类路径中保留一个标识服务器的属性文件环境类型,并将其用于.war文件中属性文件中的键值。外部属性文件也可能是一种很好的方法,可能会有一些高级配置,这些配置不会发生太大变化,并且可以在多个war文件中使用。

答案 3 :(得分:1)

可能最简单的方法是设置一个在应用程序服务之间不同的环境变量,并使用它来确定要读取的属性文件。

另一种可能性是将属性存储在数据库中,并使用以标准JNDI名称存在的数据源,但指向不同环境中的不同位置。

答案 4 :(得分:1)

我更喜欢一种EAR或一种WAR方法。从安全的角度来看,有一些重新保证并经常要求采用刚刚测试的完全相同的EAR并将其直接移动到下一个状态(测试&gt;生产)。

除容器提供的属性文件外,还有许多选项。通常,容器有一个很好的UI来维护这些值和资源。

使用数据库备份ResourceBundle的例子很多。

例如,Spring框架有几种机制可以在不费力的情况下实现。从PropertyPlaceholderConfigurer

开始

答案 5 :(得分:1)

在启动时设置一个指向属性文件位置的Systemproperty,然后在您的应用程序中拉入此属性并加载您的设置。我做的另一件事是有两个属性文件,比如default.properties和external.properties。它们包含相同的属性,但default.properties包含默认值(大多数时间设置),此文件在战争中。然后,如果你部署到env。你找到了external.properties,如果找到了,那么如果没有,你就回滚到default.properties。如果需要,这提供了覆盖属性的好方法,但也有默认设置。这适用于我的许多部署,但可能不适用于您的场景。

答案 6 :(得分:0)

绝对单一的WAR是最好的方法。在每个环境中使用相同的JNDI名称设置资源,如果您需要检测出用于业务逻辑目的的环境,请在Tomcat启动时使用System属性。

答案 7 :(得分:0)

单一构建(战争)当然是正确的方法。 但是,在涉及特定于环境的配置时,最好的方法是确保不应将所有配置.properties文件推送到所有环境。例如应将PROD属性文件复制到DEV或UAT。 还应避免使用Spring配置文件,因为它们会导致错综复杂的配置管理。