【问题标题】:Is it bad practice to include properties/configuaration files within jars?在 jar 中包含属性/配置文件是不好的做法吗?
【发布时间】:2009-07-30 19:37:21
【问题描述】:

例如:

MyApp 是一个 Web 应用程序,其中包含一个属性文件 (server.properties),该文件描述了应用程序的配置数据(例如服务器名称)。在开发阶段,server.properties 位于它自己的 IDE 项目文件夹中(它的逻辑位置)。

现在是部署 MyApp 的时候了。 IDE 使得 jar 类文件以及支持的配置文件变得非常简单。现在我们只需将 Jar 放入适当的 Web 容器中,然后我们就可以走了......

一周后... MyApp 使用的服务器配置数据需要更改。哪个更有意义?

A.在 IDE 中修改 server.properties 文件并生成一个全新的 jar 文件。重新部署。 (这意味着弹跳应用程序以进行简单的配置更改)。

B.破解打开已经部署的Jar并修改server.properties文件? (如果 server.properties 被缓存,可能必须在 MyApp 中调用刷新函数......但不需要完整的应用程序反弹。还需要记住修改源 server.properties 以便将来的部署不会恢复 server.properties到旧的服务器名称)。

C.首先将 server.properties 设置为 jar 文件的外部。与 B 的流程非常相似,只是将配置数据保存在 jar 之外(在开发和生产部署之间引入了不同的路径)

D.其他:

谢谢!

【问题讨论】:

  • 感谢大家提供的具体示例。我希望我可以将它们都标记为答案助手或其他东西。

标签: java configuration properties jar


【解决方案1】:

我会选择 D。

尝试从 .jar 外部加载属性文件,如果失败,则加载内置到 jar 中的属性。

这使您可以在每次构建时推出“现成”配置(如果仅通过一个文件,也可以降低部署的复杂性),同时还可以实现覆盖配置并且相当简单。

【讨论】:

    【解决方案2】:

    如果您使用的是 Spring,那么您可以使用属性占位符来完成这项工作。

    <!-- try and resolve the config from the filesystem first and then fallback to the classpath -->
    <context:property-placeholder location="file:config.properties, classpath:config.properties"
                                  ignore-resource-not-found="true"/>
    

    您可以在文件系统和类路径上指定资源,Spring 将首先尝试解析文件系统中的所有属性,然后回退到类路径。通过将“ignore-resource-not-found”属性指定为“true”,它将防止 Spring 在文件不存在于文件系统上时抛出异常,并允许它从类路径中解析属性。

    使用此组合还允许您将属性拆分为两个文件,例如,您可能永远不想在类路径上的文件中指定密码,并希望它们在文件系统的外部指定。文件系统中缺少的任何属性都将从类路径中解析。

    在包含以下内容的文件夹中:

    application.jar
    config.properties
    

    你应该可以使用:

    java -jar application.jar
    

    这是一个示例 config.properties 供参考:

    # This file contains properties that are used to configure the application
    database.url=127.0.0.1
    database.port=3306
    database.user=root
    database.pass=p4ssw0rd
    

    【讨论】:

      【解决方案3】:

      这取决于。如果属性文件包含打算由您的应用程序或库的用户更改的数据,那么它应该位于外部。

      如果它包含静态数据并且您创建属性文件只是为了避免对源代码中的值进行编码,或者如果文件是本地化字符串,我会将它们留在 jar 中。至少因为属性文件会邀请人们更改值;)

      【讨论】:

        【解决方案4】:

        D.

        加载 jar 中的属性。然后使用 jar-ed 属性作为默认值创建一个新的属性。然后从罐子外面加载。这允许选择自定义属性。

        【讨论】:

        • 可以对应用服务器中的 WAR 做同样的事情吗? Websphere、Jboss 等
        • @anton1980 没有线索。我从来没有处理过应用服务器
        【解决方案5】:

        请记住,在 J2EE 中,不能保证您能够从 J2EE 环境之外访问文件(不能直接访问文件)。

        您必须使用 JNDI 来指向包含您的数据的数据源,或部署工件中的属性文件。

        例如,Websphere 默认情况下不允许直接文件访问。

        【讨论】:

        • 如何在 Websphere 中通过 JNDI 访问 .properties 文件?
        • @anton1980:也许这对你有用?我不在一个使用 Websphere 的地方,所以我不能轻易地为你测试这个:stackoverflow.com/questions/12312699/…
        【解决方案6】:

        选项D。在不同的环境中你可能需要指定想要指定的环境属性,例如连接数据库或代理等。

        另外值得注意的是,在生产环境中,您可能希望快速更改属性,而无需预先打包 jar 或替换 jar 中的属性文件。

        例如数据库服务器发生故障,您需要指向不同的服务器(如果不使用数据库的负载平衡器)。因此,您需要做的就是替换数据库属性并重新启动。你可以节省很多时间。

        【讨论】:

          【解决方案7】:

          通常将代码从测试迁移到生产未更改是一个标准。这意味着您不能编辑嵌入式配置文件。此外,您可能会遇到需要更改已部署配置的情况——这通常非常麻烦。因此,我们将配置留在 jar 之外。

          对于 Java EE 应用程序,请考虑 JNDI 或类路径中的属性文件。

          我有一个 Web 应用程序,其中的配置是从相邻的 Web 应用程序中检索出来的,只是为了将两者分开。事实证明这要容易得多。

          【讨论】:

            【解决方案8】:

            我在 webapps (WARs) 中使用属性文件,但主要用于默认值和或多或少不可变的东西(因为 webapps 不应该更新它们的 WARs,即使它们可以)。

            但是,对于您所说的内容,我使用 JNDI。您可以将属性定义为 web.xml 文件中的资源。这样,在最坏的情况下,您更新的是 web.xml 而不是应用程序本身。

            对于某些服务器,有一些方法可以覆盖这些资源值而根本不触及 WAR。例如,在 Tomcat 中。

            我通常为测试、Q/A 和生产制作一个 WAR,并使用 Tomcat 的 Context xml 文件覆盖对环境敏感的资源。我认为这比构建多个 WAR 或修改 WARS 好得多,因为我正在测试的应用程序几乎与生产中的应用程序相同。

            【讨论】:

              【解决方案9】:

              我认为答案取决于您是否认为需要对配置进行版本控制。 (它们可能是生产配置或回归测试配置...)

              • 如果您不需要版本控制,那么带有覆盖属性文件的外部属性文件的选项 D 是一个不错的选择。选项 B 和 C 更容易出现问题,但如果你真的很在意,你会使用版本控制 :-)
              • 如果您需要版本控制,选项 A 可为您提供更多控制,但如果您有可能进行多个部署,您可能还希望/需要对每个部署的配置进行版本控制。一个示例是测试和生产平台的单独部署。

              以下是我们如何使用 Maven 模块和 Maven WAR 文件“叠加层”来做到这一点。

              1. 我们有多个用于 Java 代码组件的模块。这些是 JAR 模块。
              2. 我们为静态内容、JSP 和核心配置数据(Spring 布线、默认属性)提供了“基础 webapp”模块。这是一个WAR模块,所以构建的结果是一个包含以上+所有JAR文件的WAR。
              3. 每个不同的“站点配置”都是一个 WAR 模块,其中包含对属性、连接文件和内容的特定于站点的覆盖。覆盖是使用 Maven WAR“覆盖”机制描述的,并导致从“基础”WAR 和覆盖组装一个新的 WAR。

              所有这些都签入版本控制,您需要进行 Maven 构建和 WAR 部署以进行配置更改。

              【讨论】:

              • 您还可以对不会打包到 JAR 中的属性文件进行版本控制。
              【解决方案10】:

              我问过一个类似的问题。我们还没有完全弄清楚。但我们正在研究 URL 资源。直接从 SVN 读取属性文件的位置。除了属性文件,不需要更新任何东西。

              【讨论】:

              • 您的生产应用程序正在直接从 Subversion 读取您的属性文件?听起来很脆弱。
              【解决方案11】:

              我使用 Spring 开发 J2EE 应用程序。我在同一个问题上运行了很长时间,然后找到了解决方案。 我的问题是在我部署的 war 文件之外的属性文件中指定数据库属性。我找到的解决方案是使用 PropertyPlaceholderConfigurer 并指定 location 属性来定位您的系统位置,

              这很简单,而且效果很好!

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2019-04-06
                • 2013-11-14
                • 2017-06-01
                • 2013-05-15
                • 2019-11-11
                相关资源
                最近更新 更多