从java webapp中的属性文件存储属性的位置

时间:2014-06-22 09:03:38

标签: java tomcat servlets properties

不确定此问题是否曾被问过,但我似乎无法找到答案。

在webapp中加载时,存储属性的位置。 我有一个Web应用程序,其设置允许系统管理员通过用户界面更改应用程序中的设置。

例如,该应用仅允许选定的用户组访问某个页面。 我想允许系统管理员进入并设置可以转到上述页面的用户组,然后在以后更改它。

我面临的问题是,一旦加载了属性文件,我在哪里存储数据,而不是每次用户进入页面时连续加载属性文件。

我可能没有得到如何使用属性的完整概念,因此任何指导都会受到高度赞赏。

确保我可以读取用户组,可以更改用户组而无需重新加载类/应用程序并允许它是线程安全且快速的,而没有两个不同的线程具有两个不同的属性,因为我们使用负载平衡环境。使用内容共享,这是存储和访问属性文件的位置(没有任何问题,因此不寻求有关存储属性文件的位置的帮助)。

非常感谢任何帮助。

编辑1

应用程序在集群环境中运行,这意味着由于多个ServletContexts,其他应用程序服务器可能具有不同的值。

3 个答案:

答案 0 :(得分:1)

Servlet容器提供了Contexts的概念。我发现将Context作为一个用于存储内容的有用框并且像Map一样运行是有帮助的。

Java Webapp有许多不同的上下文,它们的范围不同(即上下文中保存的数据持续多长时间以及可以从中访问的位置)。有页面上下文会话上下文 Servlet上下文

页面上下文的范围最窄,只需要处理一个页面就可以持续。

会话上下文具有更大的范围,并且持续时间与单个用户会话一样长,即来自浏览器的多个请求。如果您的webapp需要身份验证,这将非常有用 - 有关经过身份验证的用户的信息将存储在会话上下文中。

Servlet上下文实际上是全局的,并且始终可供整个应用程序使用。这是我建议存储影响应用程序运行的配置属性的地方。

在Servlet中,您可以像这样访问Servlet上下文:

ServletContext context = request.getSession().getServletContext();

您可以在上下文中存储内容:

context.setAttribute("key", object);

其中key是一个字符串 - 属性的名称。

你可以像这样再次检索它:

object = context.getAttribute("key");

返回一个Object。你可以将它投射到它真正的任何类型。如果需要,可以在其中存储Properties对象:

Properties props = //... get the properties from file
context.setAttribute("props", props);

然后检索它们:

Properties props = (Properties) context.getAttribute("props");

或者您可以将各个属性存储为上下文中的单独属性。

所有上下文都以相同的方式访问。

答案 1 :(得分:1)

注册 ServletContextListener 以在服务器启动中加载Init参数和属性。

一次加载属性并使其对其他类静态可见,或者您可以将其存储在应用程序上下文中,以便从JSP和Servlet等任何位置访问它。

注意:使属性文件位置可以在web.xml中配置,而不是在Java类中对其进行硬编码。您也可以将属性文件位置检索为系统环境变量

示例代码:

public class AppServletContextListener implements ServletContextListener {
    private static Properties properties;
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        String cfgfile = servletContextEvent.getServletContext().getInitParameter("config_file");
        properties.load(new FileInputStream(cfgfile));

        // store it in application scope as well
        servletContextEvent.getServletContext().setAttribute("prop",properties);
    }

    public static Properties getProperties(){
        return properties;
    }
}

<强>的web.xml:

<listener>
    <listener-class>com.x.y.z.AppServletContextListener</listener-class>
</listener>

<context-param>
      <param-name>config_file</param-name>
      <param-value>config_file_location</param-value>
</context-param>

请查看我在同一上下文中提到的另一篇文章:


修改

如果要在运行时更改属性,请不要根据ServletContext javadoc使用Servlet上下文:

  

如果Web应用程序标记为&#34;已分发&#34;在其部署描述符中,每个虚拟机将有一个上下文实例。在这种情况下,上下文不能用作共享全局信息的位置(因为信息不会真正全球化)。使用外部资源,如数据库。

Servlet specification还在&#34; SRV.4.4.1分布式容器中的上下文属性中声明&#34;:

  

上下文属性是创建它们的JVM的本地属性。这可以防止ServletContext属性成为分布式容器中的共享内存。当需要在分布式环境中运行的servlet之间共享信息时,应将信息放入会话(请参阅第SRV.7节“会话”),存储在数据库中或设置在Enterprise JavaBeansTM组件中。

在这种情况下,您可以尝试使用在分布式环境中工作的某些第三方缓存,如下所述:

OR将所有属性存储在数据库中。

答案 2 :(得分:0)

您可以使用经典的单例模式,其中您有一个ApplicationProperties类,它为您的应用程序保存属性文件支持的全局有效值,因此您的应用程序的任何部分都不必关心如何存储属性。伪代码:

public class ApplicationProperties {

    private static final String PATH = "app.properties";

    private static final ApplicationProperties INSTANCE = new ApplicationProperties();

    private String userGroup;

    private ApplicationProperties() {
        // Load properties from PATH and populate fields.
        this.userGroup = ...
    }

    public static ApplicationProperties getInstance() {
        return INSTANCE;
    }

    public String getUserGroup() {
        return this.userGroup;
    }

    public String setUserGroup(String userGroup) {
        // Save to property file to persist.
        this.userGroup = userGroup;
    }
}

您只需要同步访问没有两个线程覆盖属性并创建竞争条件的字段。