简体   繁体   English

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

[英]How set TimeZone for each virtual host in tomcat

I have web apps for 3 regions (Mongolia,Turkmenia, etc). 我有3个地区的网络应用程序(蒙古,土库曼等)。 And they are deployed on tomcat's virtual host . 它们部署在tomcat的虚拟主机上 Now I need set timezone for each application. 现在我需要为每个应用程序设置时区 How can I do that? 我怎样才能做到这一点? I implemented ServerContextListener interface for each apps to set 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);
}

But after deploy each apps has same TimeZone. 但部署后,每个应用程序都具有相同的TimeZone。

PS: Sorry for my English :) PS:对不起我的英文:)

ZoneId , not TimeZone ZoneId ,而不是TimeZone

The terrible legacy date-time classes were supplanted years ago by the modern java.time classes with the adoption of JSR 310. 几年前,现代java.time类取代了可怕的遗留日期时间类,并采用了JSR 310。

TimeZone in replaced by ZoneId & ZoneOffset . TimeZoneZoneIdZoneOffset取代。

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

Avoid default time zone 避免默认时区

Avoid relying on the JVM's current default time zone. 避免依赖JVM的当前默认时区。

There is only one default time zone for the JVM . JVM只有一个默认时区 Calling TimeZone.setDefault immediately affects all code in all threads of all apps within that JVM. 调用TimeZone.setDefault立即影响该JVM中所有应用程序的所有线程中的所有代码。

But after deploy each apps has same TimeZone. 但部署后,每个应用程序都具有相同的TimeZone。

So you cannot set a different default time zone per web app. 因此,您无法为每个Web应用设置不同的默认时区。 If all the web apps are running in the same Servlet container, then all the web apps share the same default time zone. 如果所有Web应用程序都在同一个Servlet容器中运行,则所有Web应用程序共享相同的默认时区。

Pass desired time zone 通过所需的时区

A better approach is to explicitly pass the desired/expected time zone as the optional argument to various java.time methods. 更好的方法是将期望/预期的时区显式传递为各种java.time方法的可选参数。 For example, if you want to capture the current moment as seen in a particular time zone, pass the desired ZoneId object to the now method. 例如,如果要捕获在特定时区中看到的当前时刻,请将所需的ZoneId对象传递给now方法。

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

Rather than depend on the JVM's current default time zone, set a time zone for each of your web apps. 而不是依赖于JVM的当前默认时区,为每个Web应用程序设置时区。

ServletContextListener::contextInitialized

You were close to a solution. 你接近解决方案。 When each web app launches, you need to specify its default. 每个Web应用程序启动时,您需要指定其默认值。 The place to do that is in the contextInitialized method in your class implementing the ServletContextListener as shown in your Question. 这样做的地方是在类的contextInitialized方法中实现ServletContextListener ,如问题所示。

Inside that method, specify the desired time zone. 在该方法中,指定所需的时区。

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

But that variable goes out of scope and disappears at the end of the contextInitialized method. 但是该变量超出范围并在contextInitialized方法的末尾消失。 So we need to store a reference to that ZoneId object somewhere. 所以我们需要在某处存储对该ZoneId对象的引用。 But where? 但是哪里? The Servlet spec defines a place just for such “global” variables or constants you need across code within your app. Servlet规范为您的应用程序中的代码定义了一个所需的“全局”变量或常量的位置。

Your contextInitialized method is passed a ServletContextEvent . 您的contextInitialized方法传递给ServletContextEvent That object holds a reference to the ServletContext object representing the current instance of your web app that is launching. 该对象包含对ServletContext对象的引用,该对象表示正在启动的Web应用程序的当前实例。

ServletContext myWebAppContext = servletContextEvent.getContext() ;

Attributes (key-value store) 属性(键值存储)

That ServletContext conveniently maintains a simple key-value store of “attributes”. ServletContext方便地维护“属性”的简单键值存储。 The key is a String , the value an Object . 键是String ,值是Object We can make up a string name for our per-web-app default time zone, and pass the ZoneId as the Object value. 我们可以为每个Web应用程序的默认时区组成一个字符串名称,并将ZoneId作为Object值传递。 Pass these to ServletContext::setAttribute . 将这些传递给ServletContext::setAttribute

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

In your app's code, look up the context and attribute anytime you need. 在您的应用程序代码中,随时查看上下文和属性。 Ask the Servlet request being serviced for its context. 请求Servlet请求为其上下文提供服务。

ServletContext context = request.getServletContext() ;

Ask for the value from the stored attribute. 从存储的属性中请求值。

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

Cast the Object back to a ZoneId . Object ZoneIdZoneId We know that should work, but for defensive programming you may want to check instanceof . 我们知道应该可行,但对于防御性编程,您可能需要检查instanceof

ZoneId z = ( ZoneId ) value ;

Then proceed with your work. 然后继续你的工作。 Perhaps you want to capture the time as seen in that zone, just as we discussed above. 也许你想要捕捉在该区域中看到的时间,就像我们上面讨论的那样。

ZonedDateTime zdt = ZonedDateTime.now( z ) ;

Tip: You might want to define an enum to handle those multiple region strings for the attributes names. 提示:您可能希望定义枚举以处理属性名称的多个区域字符串。 Copy-pasting string values is risk business. 复制粘贴字符串值是风险业务。 See tutorial . 教程

Thread-safety 线程安全

Note that while each web app instance has its own ZoneId object, that object is being shared across threads. 请注意,虽然每个Web应用程序实例都有自己的ZoneId对象,但该对象是跨线程共享的。 A Servlet environment is by definition highly-threaded, each request being serviced on a thread. 根据定义,Servlet环境是高度线程化的,每个请求都在一个线程上提供服务。 So that ZoneId is being shared across any number of threads. 因此, ZoneId可以在任意数量的线程中共享。 But that is okay. 但那没关系。 Fortunately, the java.time classes are thread-safe by design, using the immutable objects pattern. 幸运的是, java.time类在设计时使用不可变对象模式是线程安全的。

Obligatory Servlet threading concurrency tip: Anyone doing Servlet coding should be reading and re-reading this book: Java Concurrency in Practice by Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, Doug Lea. 强制性Servlet线程并发技巧:任何进行Servlet编码的人都应该阅读并重新阅读本书:Brian Goetz,Tim Peierls,Joshua Bloch,Joseph Bowbeer,David Holmes,Doug Lea撰写的Java Concurrency in Practice

You can set JVM timezone for tomcat. 您可以为tomcat设置JVM时区。 For that you need to add below option in your JVM options, in tomcat configuration file. 为此,您需要在tomcat配置文件中的JVM选项中添加以下选项。

-Duser.timezone=UTC

Use your timezone in place of UTC. 使用您的时区代替UTC。 It will start your JVM in that timezone. 它将在该时区启动您的JVM。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM