在Java构建过程中更改常量的最佳方法

时间:2008-12-31 19:47:20

标签: java configuration tomcat ant build-automation

我继承了一个在Tomcat下运行的Java应用程序(servlets)。由于历史原因,代码具有不同的“外观和感觉”选项,具体取决于应用程序的部署位置(基本上是品牌推广)。

有几个常量控制着这个品牌推广过程,它们具有不同的功能,不应该压缩成一个常量(即BRAND,MULTI-LANGUAGE,加上图标和css样式表的位置等)。

目前,开发团队必须手动更改常量(它们至少本地化在一个数据类中并有详细记录),然后使用ANT重新编译应用程序。

至少假设Ant 1.8和Java 6.x,自动执行此过程的最佳方法是什么?

我知道使用编译器参数没有任何好的解决方案(就像在C或C ++中可以做到的那样),并且我倾向于使用一些“最好的方法”来编辑包含常量的源文件,或者将它们放入另一个文件并使用ant构建过程交换它们。我希望得到的结果可以使用像“ant build brand-x”这样的东西,改变品牌会改变结果。

谢谢,

-Richard

6 个答案:

答案 0 :(得分:9)

将您的值放入属性文件中,例如“myapp.properties”,然后在启动时从类路径将它们加载到常量中(请参阅下文,了解它如何适合构建过程):

public class Constants
{
    private static final Properties props = new Properties();
    public static final String MY_CONSTANT;

    static
    {
        InputStream input = Constants.class.getResourceAsStream("/myapp.properties");
        if(input != null)
        {
           try
           {
              properties.load(input);
           }
           catch(IOException e)
           {
              // TODO log error
           }
        }

        // Initialize constants (dont' forget defaults)
        MY_CONSTANT = properties.getProperty("constant", "default");
        // .. other constants ...
    }
}

现在,为每个品牌设置一个单独的属性文件。通过-D或build.properties将其名称传递给ANT,然后在将jar文件(或者用于它)之前将文件复制到构建目录中。

显然,上面的代码可行,但有很多方法可以清理它并使其成为防弹。

答案 1 :(得分:2)

使用Ant中的替换任务来更改值。

答案 2 :(得分:1)

还有一种“spring”方式,即使用属性文件,以及从属性中提取值并将它们注入需要它们的类的bean,例如:

<bean id="propertyPlaceholder"  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:configuration.properties" />
</bean>

然后,您可以使用“类似ant”的语法注入属性:

<bean id="connectionPool"  class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
    <property name="databaseName" value="mydb" />
    <property name="url" value="${db.url}" />
    ...

这可能需要比你想要的更多的重写。如果你要在每次编译时改变常量,我会注意这个问题(如果你正在使用静态韵母,那就是)。

public class Foo {
 public static final int SOME_CONSTANT=1;
..
}

public class Bar {
  ...
   int x=5+Foo.SOME_CONSTANT;
  ...
}

如果然后将Foo中的SOME_CONSTANT更改为2但不重新编译Bar,则为SOME_CONSTANT保留值1,因为编译了静态韵母(因为编译器发现它不需要重复编码)他们再次出局)。

答案 3 :(得分:1)

我更喜欢使用ant的expandproperties过滤器而不是替换任务。使用替换任务,构建文件趋于增长,主要是标记化。 expandproperties允许您直接在文本中嵌入ant属性。

<copy file="from" tofile="to">
  <filterchain>
    <expandproperties />
  </filterchain>
</copy>

答案 4 :(得分:1)

我有一个适合这种特殊情况的解决方案。我已经将Ant替换任务与常量类的“已保存”版本结合使用:

<target name="one" description="constant substitution #1">
  <delete file="./tme3/MyConst.java" />
  <copy file="./save/MyConst.java" tofile="./tme3/MyConst.java" />
  <replace file="./tme3/MyConst.java" token="@BRANDING@" value="ONE_BRAND"/>
  <replace file="./tme3/MyConst.java" token="@STYLESHEET@"
           value="../stylesheet/onebrand.css"/>
  <replace file="./tme3/MyConst.java" token="@FAVICON@" value="../images/onebrand.ico"/>
  <replace file="./tme3/MyConst.java" token="@SHOW_LANGUAGES@" value="false"/>
</target>

我只是制作了这个块的副本并更改了我需要的案例的替换 - 在我的特定情况下,现在有3套,但更多的预期。

感谢所有人的回复。

答案 5 :(得分:0)

使用Ant property files,并使用“-Dbrand = X”进行构建。