不确定此问题是否曾被问过,但我似乎无法找到答案。
在webapp中加载时,存储属性的位置。 我有一个Web应用程序,其设置允许系统管理员通过用户界面更改应用程序中的设置。
例如,该应用仅允许选定的用户组访问某个页面。 我想允许系统管理员进入并设置可以转到上述页面的用户组,然后在以后更改它。
我面临的问题是,一旦加载了属性文件,我在哪里存储数据,而不是每次用户进入页面时连续加载属性文件。
我可能没有得到如何使用属性的完整概念,因此任何指导都会受到高度赞赏。
确保我可以读取用户组,可以更改用户组而无需重新加载类/应用程序并允许它是线程安全且快速的,而没有两个不同的线程具有两个不同的属性,因为我们使用负载平衡环境。使用内容共享,这是存储和访问属性文件的位置(没有任何问题,因此不寻求有关存储属性文件的位置的帮助)。
非常感谢任何帮助。
编辑1
应用程序在集群环境中运行,这意味着由于多个ServletContexts,其他应用程序服务器可能具有不同的值。
答案 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;
}
}
您只需要同步访问没有两个线程覆盖属性并创建竞争条件的字段。