【问题标题】:config files for a webapplication - load once and store where?Web 应用程序的配置文件 - 加载一次并存储在哪里?
【发布时间】:2011-03-10 09:14:37
【问题描述】:

我有一堆可以根据环境更改的属性(配置)。但是,一旦部署了 Web 应用程序,这些值就不会改变。所以考虑到有一个 application.properties 文件,我想在正常的程序流程中多次读取它。

我知道我可以在服务器启动时加载这些。但是,从后端的简单 Java 类访问这些的最佳实践是什么?这些业务类与 servlet 等无关,也不依赖于 webapp。

所以今天我通过 ServletContext 加载属性。然后呢?我应该将它们保存在哪里以便其他对象可以轻松访问而无需再次执行 fileInputStream.load?

谢谢。

【问题讨论】:

    标签: java servlets properties


    【解决方案1】:

    实现ServletContextListener

    这是一个基本的启动示例:

    public class Config implements ServletContextListener {
        private static final String ATTRIBUTE_NAME = "config";
        private Properties config = new Properties();
    
        @Override
        public void contextInitialized(ServletContextEvent event) {
            try {
                config.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"));
            } catch (IOException e) {
                throw new SomeRuntimeException("Loading config failed", e);
            }
            event.getServletContext().setAttribute(ATTRIBUTE_NAME, this);
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent event) {
            // NOOP.
        }
    
        public static Config getInstance(ServletContext context) {
            return (Config) context.getAttribute(ATTRIBUTE_NAME);
        }
    
        public String getProperty(String key) {
            return config.getProperty(key);
        }
    }
    

    你在web.xml注册如下:

    <listener>
        <listener-class>com.example.Config</listener-class>
    </listener>
    

    您可以在 servlet 中访问,如下所示:

    Config config = Config.getInstance(getServletContext());
    String property = config.getProperty("somekey");
    

    再三考虑之后,这些属性因此 100% 特定于业务层,而不是 Web 应用程序本身?那么ServletContextListener 确实笨拙且耦合太紧。只需为业务层提供自己的Config 类,该类从类路径加载属性并将其缓存在一些static 变量中(Map&lt;String, Properties&gt; 也许?)。

    【讨论】:

    • 感谢您的回复。正是我在做什么。也许我应该更清楚。我试图避免在我的域对象中使用 ServletContext 或 ServletContextListener。我想将它存储在 POJO 中并访问它。但是我正在努力是否创建一个单例属性对象并在那里加载属性。有什么想法吗?
    • 单例是相当可观的,但仅仅在某个类中将Properties 分配为static 变量也绰绰有余。
    • 你能解释一下为什么静态是一个不好的解决方案吗?我不想引入框架依赖项来加载配置文件......主要是,我试图避免使用 ServletContext 等,因为 junit 测试对于业务类来说是一种痛苦。今天我可以很开心地测试它们......
    • static + 单元测试 = aaaaargh!!顺便说一句:加载配置文件不需要框架。仅针对您已经在使用的情况。否则只是重新发明普通框架已经做的事情。 ServletContextListener 等等。
    • 我同意静态问题。但我不知道快速将其插入并让它工作类型的罐子,我可以包括在内。我正在使用 RESTEasy 顺便说一句。除了 ServletContextListener,我只是没有一个好的钩子。还有什么具体的例子吗?
    【解决方案2】:

    将您的配置类/属性放在一个 jar 文件中,然后将该 jar 文件放在 WEB-INF/lib 中。然后,您可以在 Web 应用程序中的任何需要的地方通过普通的类路径资源工具访问它们。

    【讨论】:

      【解决方案3】:

      您应该拥有对这些属性的静态引用,并以这种方式访问​​它们。您最终会将它们读入内存一次,并将它们保留在那里。这样,您就不必在运行时多次访问磁盘。

      所以,假设你有一个班级AppProperties

      public class AppProperties {
        private static Properties props;
      
        protected static loadProperties(File propsFile) {
          ... read from disk, and set props static member ...
        }
      
        public static getProperties() {
          return props;
        }
      }
      

      从您的初始化程序 servlet,您可以调用 loadProperties 从磁盘读取属性。然后,在您的应用程序代码中,访问属性:

      String myProp = AppProperties.getProperties().getProperty("myProp");
      

      【讨论】:

      • 您能详细说明一下吗?来自哪里的静态引用?
      • 是的,对不起,我本打算从一开始就填写这个答案,但我被“现实世界”中的某些东西分心了:)
      • 我想这与我拥有的 ServletContextListener 相结合。这似乎是目前最简单的解决方案。
      • 是的,最大的好处是业务逻辑代码只需要引用AppProperties类,不需要任何JEE的东西。然后,您可以让您的单元测试 setup 方法初始化属性,就像您的 ServletContextListener 通常一样。
      【解决方案4】:

      如果您的应用服务器支持,您可以使用 JNDI。

      在这里查看我的问题(和答案):Spring deployment-level configuration

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-25
        • 2015-03-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多