gpt4 book ai didi

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

转载 作者:搜寻专家 更新时间:2023-11-01 03:20:28 24 4
gpt4 key购买 nike

我有适用于 3 个地区(蒙古、土库曼尼亚等)的网络应用。并且都部署在tomcat的虚拟主机上。现在我需要为每个应用程序设置时区。我怎样才能做到这一点?我为每个应用程序实现了 ServerContextListener 接口(interface)来设置 TimeZone:

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

但在部署后每个应用程序都有相同的时区。

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

最佳答案

ZoneId,不是TimeZone

多年前,随着 JSR 310 的采用,现代 java.time 类取代了糟糕的遗留日期时间类。

TimeZone 替换为 ZoneId & ZoneOffset .

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

避免默认时区

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

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

But after deploy each apps has same TimeZone.

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

传递所需的时区

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

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

与其依赖于 JVM 当前的默认时区,不如为您的每个 Web 应用程序设置一个时区。

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 .

线程安全

请注意,虽然每个网络应用程序实例都有自己的 ZoneId对象,该对象正在跨线程共享。根据定义,Servlet 环境是高度线程化的,每个请求都在一个线程上得到服务。这样 ZoneId 就可以在任意数量的线程之间共享。但没关系。幸运的是,java.time 类是 thread-safe通过设计,使用 immutable objects图案。

强制性 Servlet 线程并发技巧:任何进行 Servlet 编码的人都应该阅读并重读这本书:Java Concurrency in Practice作者:Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowbeer、David Holmes、Doug Lea。

关于java - tomcat中如何为每个虚拟主机设置TimeZone,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31934995/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com