Как установить часовой пояс в Tomcat для одного веб-приложения?
Каков наилучший способ установить часовой пояс в Tomcat для одного веб-приложения? Я видел варианты изменения параметров командной строки или переменных окружения для Tomcat, но есть ли способ установить его автономно в файле WAR и не зависит от какой-либо конфигурации Tomcat?
Изменить: переопределить, я ищу решение, которое может содержаться в WAR файле, не зависящее от конфигурации Tomcat. Другими словами, можно ли настроить одно веб-приложение на другой часовой пояс, чем другие приложения, работающие в одном экземпляре Tomcat?
Ответы
Ответ 1
Единственный способ, которым я нашел, - установить фильтр и изменить часовой пояс в фильтре,
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
TimeZone savedZone = TimeZone.getDefault();
TimeZone.setDefault(webappZone);
chain.doFilter(request, response);
TimeZone.setDefault(savedZone);
}
setDefault()
изменяет зону для потока. Таким образом, все, что работает в потоке внутри фильтра, будет иметь другой часовой пояс по умолчанию. Мы должны изменить его, потому что поток используется другими приложениями. Вам также необходимо сделать то же самое для методов init()
, destroy()
и любого другого потока, который вы можете запустить в своем приложении.
Мне пришлось это делать, потому что сторонняя библиотека принимает по умолчанию часовой пояс, и у нас нет исходного кода. Это было беспорядок, потому что это изменяет часовой пояс журнала, но мы не хотим, чтобы он регистрировался в разное время. Правильный способ справиться с этим - использовать определенный часовой пояс в любом временном значении, доступном для конечных пользователей.
Ответ 2
Задайте системную переменную CATALINA_OPTS=-Duser.timezone=America/Denver
Вы также можете указать CATALINA_OPTS в файле $TOMCAT_HOME/bin/catalina.sh или% TOMCAT_HOME%\bin\catalina.bat.
Здесь список допустимых часовых поясов.
Источник
Ответ 3
EDIT: Я ошибся. Это редактирование исправляет его.
Ответ заключается в том, что вы не можете переносить часовой пояс (по умолчанию) для одного веб-приложения. Но если вы используете Java 6 (по крайней мере), класс java.util.TimeZone
реализует методы часового пояса по умолчанию getDefault()
, setDefault()
и setDefault(TimeZone)
, используя наследуемый поток local. Другими словами, вызов setDefault()
влияет только на текущий поток и будущие дочерние потоки.
Поведение не описано в Sun Javadocs. Он работает на Java 6 и 5 (см. Выше), но нет никаких гарантий, что он будет работать в более старых или более новых Sun JRE. Тем не менее, я был бы очень удивлен, если бы Sun решила изменить/вернуться к "глобальной" модели для TimeZone по умолчанию. Это сломает слишком много существующих приложений, и, кроме того, глобальные переменные BAD.
Ответ 4
В JDK 6 Sun/Oracle изменила реализацию Timezone. В JDK 5.0 setDefault всегда устанавливает часовой пояс в локальной переменной потока, а не через JVM, и это вызвало несколько проблем. Sun признала это ошибкой и исправлена в JDK 1.6.
В JDK 1.6 (я проверил исходный код для JDK 1.6 и JDK 1.7), если JVM не запущен с менеджером безопасности (или он не установлен с помощью System.SetsecurityManager()
), метод setDefault
устанавливает его глобально через JVM, а не в конкретном потоке. Если вы хотите установить его только для данного потока, вам необходимо запустить JVM с помощью менеджера безопасности.
Когда вы запускаете Tomcat JVM с менеджером безопасности, вам необходимо предоставить индивидуальные разрешения, которые для нас не были стартовыми, поскольку мы опаздывали в цикле выпуска. Следовательно, в файле политики безопасности мы предоставили все разрешения, и мы переопределили менеджер безопасности JAVA по умолчанию, чтобы выборочно запретить доступ к часовому поясу. Из-за ленивой проблемы с инициализацией с классом Timezone мне нужно было вызвать Timezone.getDefault()
в статическом блоке, который запустит класс Timezone до запуска SecurityManager.
Вот моя тестовая программа.
- Файл политики test.policy
grant {
permission java.security.AllPermission;
};
- Пользовательский диспетчер безопасности
import java.security.Permission;
import java.util.TimeZone;
public class CustomSecurityManager extends SecurityManager {
static {
TimeZone.getDefault().getDisplayName();
}
public CustomSecurityManager() {
super();
}
public void checkPermission(Permission perm) throws SecurityException,NullPointerException
{
String propertyName = perm.getName();
String actionName = perm.getActions();
if(propertyName != null && actionName != null)
{
if(propertyName.equalsIgnoreCase("user.timezone")
&& actionName.equalsIgnoreCase("write"))
{
throw new SecurityException("Timezone write is not permitted.");
}
}
}
}
- Параметры запуска JVM
-Djava.security.manager = CustomSecurityManager -Djava.security.policy = C:/workspace/test/src/test.policy
Ответ 5
Просмотрите SimpleTimeZone. Вы можете создать экземпляр на основе идентификатора часового пояса и использовать его для отображения дат/времени с использованием этого часового пояса. Если вы хотите, вы можете прочитать этот идентификатор из конфигурационного файла проекта.
Ответ 6
Лучший способ - изменить веб-приложение, чтобы он принимал явную настройку часового пояса через web.xml вместо того, чтобы использовать часовой пояс JVM по умолчанию.
Ответ 7
http://seamframework.org/Documentation/JSFEnhancementDefaultApplicationTimeZone
Ответ 8
С Java 7/Tomcat 7 существует обходное/хакерское решение, которое позволяет разработчику устанавливать уникальный часовой пояс для каждого веб-клиента. Мы должны были реализовать это в нашем приложении, поскольку нам приходилось поддерживать несколько веб-приложений, которые запускаются с разными часовыми поясами по умолчанию в одной JVM.
Другие решения, которые я видел при переполнении стека, не полностью устраняют проблему.
- Использование Timezone.setDefault() не работает, поскольку оно изменяет часовой пояс на JVM.
- Использование сервлет-фильтров полностью небезопасно и не учитывает дочерние потоки.
- Использование подходов SecurityManager также не учитывает проблемы с часовым поясом, связанные с дочерними потоками.
Я также изучил исходный код Java для TimeZone, я нашел способ вернуть динамический часовой пояс в качестве часового пояса по умолчанию для всех вызывающих абонентов, введя пользовательскую реализацию интерфейса JavaAWTAccess. Это можно сделать, посмотрев загрузчик класса Thread и определив фактический контекст webapp из него, а затем обработав его соответствующим образом на основе некоторого имени webapp для отображения часового пояса.
Еще раз, это специфический сервер приложений, и он должен быть выполнен по-разному для Tomcat, Jetty, Jboss и т.д. Этот подход также специфичен для JVM-реализации (работает только на Oracle/Sun), но я считаю, что он может быть расширен до OpenJDK и другие.
У нас есть проверенное рабочее решение для Oracle JDK 7 SE + Tomcat 7, развернутое как на Windows, так и на Linux, размещающее несколько веб-приложений в разных часовых поясах.
Ответ 9
Вы также можете использовать аргумент VM для его определения
-Djdk.util.TimeZone.allowSetDefault=true