Мне интересно поработать над драйвером JDBC PostgreSQL, чтобы помочь с реализацией Statement.setQueryTimeout(...)
, одной из наиболее проблемных дыр в спецификации спецификации в драйвере.Для этого мне нужен портативный способ получить таймер или установить будильник / обратный вызов, который работает на всех серверах приложений Java, контейнерах сервлетов и в средах Java SE.
Кажется, что это не так просто, кактак и должно быть, и я застрял настолько, что намекаю на вашу милость. Как, черт возьми, я могу сделать простой обратный вызов таймера, который работает в контейнерах Java SE, Java EE и сервлетов?
При необходимости я могу выдержать выполнение отдельных выпусков -ee и -se,но это крайне нежелательно.Релизы для каждого контейнера абсолютно непрактичны, хотя автоматически выбираемые адаптеры для каждого контейнера могут быть приемлемыми, если они сильно нежелательны.
Драйвер PgJDBC должен работать на старых серверах приложений в старых версиях JVM, но я немалейшее беспокойство, если время ожидания оператора доступно только в версии драйвера JDBC4 для современных контейнеров и JVM.Уже имеется инфраструктура условной компиляции, позволяющая выпускать драйверы JDBC3 / JDK 1.4 и JDBC4 / JDK 1.5, поэтому код, который работает только под 1.5 или даже 1.6, не является проблемой.
(правка): Anдобавленная сложность заключается в том, что драйвер JDBC может быть развернут пользователями:
- как модуль контейнера или встроенный компонент, который запускается при запуске контейнера;
- как отдельный объект развертывания, который можетбыть развернутым и повторно развернутым во время выполнения;или
- Встроенный в их приложение
war
или ear
... и нам необходимо поддерживать все эти сценарии, желательно без необходимости настраивать пользовательские приложения!Если мы не можем поддерживать все эти сценарии, ему нужно, по крайней мере, работать без поддержки времени ожидания оператора и терпеть неудачу из-за невозможности поддержки времени ожидания оператора.
Ах, напишите один раз, запуститеanwwhere ....
Я не могу просто использовать java.util.Timer
или java.util.concurrent
:
Я вижу общие утверждения, что использование java.util.Timer
или утилит параллелизма Java SE (JSR-166) в пакете java.util.concurrent
не рекомендуется в Java EE, но редко какие-либо подробности. Предложение JSR 236 говорит, что:
java.util.Timer, java.lang.Thread и утилиты параллелизма Java SE (JSR-166) в java.util.concurrency (sic).) пакет никогда не должен использоваться в управляемых средах, так как он создает потоки вне области действия контейнера.
Чуть больше чтения говорит о том, что вызовы из неуправляемых потоков не получат контейнерные сервисы, поэтому во всем приложении все может сломаться захватывающими и неожиданными способами.Учитывая, что вызов таймера может привести к возникновению исключения, генерируемого PgJDBC и распространяющегося в код пользовательского приложения, это важно.
(edit): Сам драйвер JDBC не требует каких-либо контейнерных сервисов поэтому мне все равно, работают ли они в его потоках таймера, если эти потоки никогда не запускают какой-либо пользовательский код.Проблема заключается в надежном обеспечении того, что они этого не делают.
Уровень абстракции таймера JSR 236 не функционирует
JSR 236 не функционирует, и я не вижу замены, удовлетворяющей тем же требованиям дляпереносимые таймеры.
Я также не могу найти никаких ссылок на переносимый способ для нескольких контейнеров, чтобы получить таймер, объединенный в контейнер.Если бы я мог получить таймер из JNDI на контейнерах и вернуться к прямому созданию экземпляра, где получение одного из JNDI не удалось, это было бы нормально ... но я даже не могу найти способ сделать это.
EJBтаймеры не подходят
Существуют таймеры EJB, но они не подходят для низкоуровневых вещей, таких как реализация драйвера JDBC, потому что они:
- постоянны при перезапуске контейнера или машины
- высокие издержки
- могут быть реализованы с использованием базы данных для сохранения таймера
- ориентировано на рабочее время, а не на машинное время
- недоступно в простых контейнерах сервлетов
- недоступно на серверах приложений EE "веб-профиль"
Так что таймеры EJB могут быть полностью исключены из списка.
Я не могу накатить свою нить таймера
Те же проблемы, которые не позволяют использовать java.util.Timer
и друзей, не позволяют мне запускать собственный поток таймеров и управлять своими собственными таймерами. Это не стартер.
Спецификация Java EE гласит:
Корпоративный компонент не должен пытаться управлять потоками. Корпоративный компонент не должен пытаться запустить, остановить, приостановить или возобновить поток или изменить приоритет или имя потока. Корпоративный компонент не должен пытаться управлять группами потоков.
и в учебнике EE написано :
Адаптеры ресурсов, которые неправильно используют потоки, могут поставить под угрозу всю среду сервера приложений. Например, адаптер ресурсов может создать слишком много потоков или может неправильно освободить созданные им потоки. Плохая обработка потоков препятствует завершению работы сервера приложений и влияет на производительность сервера приложений, поскольку создание и удаление потоков являются дорогостоящими операциями.
WorkManager не работает с таймерами
Существует javax.resource.spi.work.WorkManager , но (а) он предназначен для использования на стороне поставщика услуг, а не на стороне приложения, и (б) он не предназначен для таймеров. Таймер, вероятно, может быть взломан при использовании элемента «Работа», который спит с таймаутом, но в лучшем случае он уродлив и, вероятно, будет весьма неэффективным.
Не похоже, что он будет работать и на Java SE.
Архитектура Java Connector (JCA)
Как указано в руководстве по Java EE , архитектура коннектора может быть жизнеспособным вариантом для контейнеров EE. Однако, опять же, контейнеры сервлетов, такие как Tomcat или Jetty, могут не поддерживать его.
Я также обеспокоен влиянием производительности по этому маршруту.
Так что я застрял
Как мне выполнить эту простую задачу?
Мне нужно написать новый ThreadPoolExecutor
, который получает потоки из контейнера через JNDI, а затем использовать его в качестве основы для нового ScheduledThreadPoolExecutor
? Если да, есть ли переносимый способ получения потоков из контейнера или мне нужен поиск JNDI для каждого контейнера и код адаптера?
Мне не хватает чего-то глупого и ослепительно очевидного?
Как другие библиотеки, которым требуется асинхронная работа, таймеры или обратные вызовы, обрабатывают переносимость между Java EE и Java SE?