如何在tomcat中为每个虚拟主机设置TimeZone

时间:2015-08-11 06:49:47

标签: java tomcat7 virtual-hosts

我有 3个地区(蒙古,土库曼等)的网络应用程序。它们部署在 tomcat的虚拟主机上。现在我需要为每个应用程序设置 timezone 。我怎样才能做到这一点? 我为每个应用设置了 ServerContextListener 接口,以设置 TimeZone

@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
    TimeZone timeZone=TimeZone.getTimeZone("Asia/Ulan_Bator");
//  TimeZone timeZone=TimeZone.getTimeZone("Asia/Ashgabat");
    timeZone.setDefault(timeZone);
}

但在部署后,每个应用都有相同的TimeZone。

P.S:对不起我的英文:)

2 个答案:

答案 0 :(得分:2)

ZoneId,而不是TimeZone

可怕的传统日期时间类在几年前被现代的 java.time 类所取代,并采用了JSR310。

TimeZone替换为ZoneIdZoneOffset

ZoneId z = ZoneId.of( "Asia/Ulan_Bator" ) ;

避免使用默认时区

避免依赖JVM当前的默认时区。

JVM仅 一个默认时区。调用TimeZone.setDefault将立即影响该JVM中所有应用程序的所有线程中的所有代码。

  

但是在部署后,每个应用程序都具有相同的TimeZone。

因此,您不能为每个Web应用程序设置其他默认时区。如果所有Web应用程序都在同一个Servlet容器中运行,则所有Web应用程序共享相同的默认时区。

通过所需的时区

一种更好的方法是将所需的/期望的时区作为可选参数显式传递给各种 java.time 方法。例如,如果要捕获在特定时区看到的当前时刻,请将所需的ZoneId对象传递给now方法。

ZoneId z = ZoneId.of( "Asia/Ashgabat" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;

为每个Web应用程序设置时区,而不是依赖JVM当前的默认时区。

ServletContextListener::contextInitialized

您已接近解决方案。启动每个Web应用程序时,您需要指定其默认值。这样做的地方是您的类中实现contextInitialized的类中的ServletContextListener方法,如您的问题所示。

在该方法内,指定所需的时区。

ZoneId z = ZoneId.of( "Asia/Ashgabat" ) ;

但是该变量超出范围,并在contextInitialized方法的结尾消失。因此,我们需要在某个地方存储对该ZoneId对象的引用。但是哪里? Servlet规范仅为应用程序中跨代码所需的“全局”变量或常量定义了一个位置。

您的contextInitialized方法被传递了ServletContextEvent。该对象包含对ServletContext对象的引用,该对象代表正在启动的Web应用程序的当前实例。

ServletContext myWebAppContext = servletContextEvent.getContext() ;

属性(键值存储)

ServletContext可以方便地维护“属性”的简单键值存储。密钥是String,值是Object。我们可以为每个Web应用程序的默认时区组成一个字符串名称,并将ZoneId传递为Object值。将它们传递给ServletContext::setAttribute

String key = "com.example.acme_webapp.zoneid" ;
Object value = ZoneId.of( "Asia/Ashgabat" ) ;
myWebAppContext.setAttribute( key , value ) ;

在应用程序的代码中,look up the context并在需要时进行属性分配。向正在处理的Servlet请求询问其上下文。

ServletContext context = request.getServletContext() ;

询问存储的属性中的值。

Object value = context.getAttribute( "com.example.acme_webapp.zoneid.mongolia" ) ;

Object放回ZoneId。我们知道这应该可行,但是对于防御性编程,您可能需要检查instanceof

ZoneId z = ( ZoneId ) value ;

然后继续您的工作。就像我们上面讨论的那样,也许您想捕获在该区域中看到的时间。

ZonedDateTime zdt = ZonedDateTime.now( z ) ;

提示:您可能需要定义一个枚举来处理属性名称的多个区域字符串。复制粘贴字符串值是一项风险业务。参见tutorial

线程安全

请注意,尽管每个Web应用程序实例都有其自己的ZoneId对象,但是该对象正在线程之间共享。根据定义,Servlet环境是高度线程化的,每个请求都在线程上进行服务。这样ZoneId就可以在任意数量的线程之间共享。但这没关系。幸运的是, java.time 类是使用thread-safe模式设计的immutable objects类。

强制性的Servlet线程并发技巧:任何进行Servlet编码的人都应该阅读并重新阅读本书:Java Concurrency in Practice,作者:布莱恩·格茨,蒂姆·皮尔斯,约书亚·布洛赫,约瑟夫·鲍比尔,戴维·霍尔姆斯,道格·里阿。 >

答案 1 :(得分:0)

您可以为tomcat设置JVM时区。为此,您需要在Tomcat选项的tomcat配置文件中添加以下选项。

-Duser.timezone=UTC

使用您的时区代替UTC。它将在该时区启动您的JVM。