How set TimeZone for each virtual host in tomcat

时光怂恿深爱的人放手 提交于 2020-01-03 17:06:04

问题


I have web apps for 3 regions(Mongolia,Turkmenia, etc). And they are deployed on tomcat's virtual host. Now I need set timezone for each application. How can I do that? I implemented ServerContextListener interface for each apps to set 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.

P.S: Sorry for my English :)


回答1:


ZoneId, not TimeZone

The terrible legacy date-time classes were supplanted years ago by the modern java.time classes with the adoption of JSR 310.

TimeZone in replaced by ZoneId & ZoneOffset.

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

Avoid default time zone

Avoid relying on the JVM’s current default time zone.

There is only one default time zone for the JVM. Calling TimeZone.setDefault immediately affects all code in all threads of all apps within that JVM.

But after deploy each apps has same TimeZone.

So you cannot set a different default time zone per web app. If all the web apps are running in the same Servlet container, then all the web apps share the same default time zone.

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. 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 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.

ServletContextListener::contextInitialized

You were close to a solution. When each web app launches, you need to specify its default. The place to do that is in the contextInitialized method in your class implementing the ServletContextListener as shown in your Question.

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. So we need to store a reference to that ZoneId object somewhere. But where? The Servlet spec defines a place just for such “global” variables or constants you need across code within your app.

Your contextInitialized method is passed a ServletContextEvent. That object holds a reference to the ServletContext object representing the current instance of your web app that is launching.

ServletContext myWebAppContext = servletContextEvent.getContext() ;

Attributes (key-value store)

That ServletContext conveniently maintains a simple key-value store of “attributes”. The key is a String, the value an Object. We can make up a string name for our per-web-app default time zone, and pass the ZoneId as the Object value. Pass these to 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.

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. We know that should work, but for defensive programming you may want to check 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. A Servlet environment is by definition highly-threaded, each request being serviced on a thread. So that ZoneId is being shared across any number of threads. But that is okay. Fortunately, the java.time classes are thread-safe by design, using the immutable objects pattern.

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.




回答2:


You can set JVM timezone for tomcat. For that you need to add below option in your JVM options, in tomcat configuration file.

-Duser.timezone=UTC

Use your timezone in place of UTC. It will start your JVM in that timezone.



来源:https://stackoverflow.com/questions/31934995/how-set-timezone-for-each-virtual-host-in-tomcat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!