Ответ 1
Я попытался понять это, так как это кажется таким интересным делом. Я публикую свои выводы здесь, хотя я чувствую, что, возможно, все еще что-то неправильно понял или сделал некоторые слишком надуманные упрощения. Собственно, также возможно, что я полностью неправильно понял ваше дело, и этот ответ бесполезен (если так, я извиняюсь).
То, что я собрал здесь, основано на двух понятиях:
- глобальное состояние сервера приложений (я использую
System.props
, но это может быть не лучший выбор - возможно, некоторые временные файлы будут лучше) - глобальное состояние, специфичное для контейнера (что означает все классы, загружаемые контейнером
ClassLoader
)
Я предлагаю метод EmbeddedEngineHandler.loadEmbeddedEngineIfNeeded
, который будет вызываться:
- во время регистрации вашего водителя
- в вашем статическом инициализаторе реализации
javax.sql.DataSource
(если вся эта работаDataSource
-related работает именно так - я мало знаю об этом)
Если я правильно понял, вам не нужно Runtime.removeShutdownHook
называть Runtime.removeShutdownHook
.
Главное, что я здесь не уверен в этом - если драйвер развернут глобально, будет ли он зарегистрирован до инициализации любого сервлета? Если нет, то я понял, что это неправильно, и это не сработает. Но может ли после этого осмотреть ClassLoader
EmbeddedEngineHandler
?
Это EmbeddedEngineHandler
:
final class EmbeddedEngineHandler {
private static final String PREFIX = ""; // some ID for your library here
private static final String IS_SERVLET_CONTEXT = PREFIX + "-is-servlet-context";
private static final String GLOBAL_ENGINE_LOADED = PREFIX + "-global-engine-loaded";
private static final String TRUE = "true";
private static volatile boolean localEngineLoaded = false;
// LOADING
static void loadEmbeddedEngineIfNeeded() {
if (isServletContext()) {
// handles only engine per container case
loadEmbeddedEngineInLocalContextIfNeeded();
} else {
// handles both normal Java application & global driver cases
loadEmbeddedEngineInGlobalContextIfNeeded();
}
}
private static void loadEmbeddedEngineInLocalContextIfNeeded() {
if (!isGlobalEngineLoaded() && !isLocalEngineLoaded()) { // will not load if we have a global driver
loadEmbeddedEngine();
markLocalEngineAsLoaded();
}
}
private static void loadEmbeddedEngineInGlobalContextIfNeeded() {
if (!isGlobalEngineLoaded()) {
loadEmbeddedEngine();
markGlobalEngineAsLoaded();
Runtime.getRuntime().addShutdownHook(new Thread(EmbeddedEngineHandler::unloadEmbeddedEngine));
}
}
private static void loadEmbeddedEngine() {
}
static void unloadEmbeddedEngine() {
}
// SERVLET CONTEXT (state shared between containers)
private static boolean isServletContext() {
return TRUE.equals(System.getProperty(IS_SERVLET_CONTEXT));
}
static void markAsServletContext() {
System.setProperty(IS_SERVLET_CONTEXT, TRUE);
}
// GLOBAL ENGINE (state shared between containers)
private static boolean isGlobalEngineLoaded() {
return TRUE.equals(System.getProperty(GLOBAL_ENGINE_LOADED));
}
private static void markGlobalEngineAsLoaded() {
System.setProperty(GLOBAL_ENGINE_LOADED, TRUE);
}
// LOCAL ENGINE (container-specific state)
static boolean isLocalEngineLoaded() {
return localEngineLoaded;
}
private static void markLocalEngineAsLoaded() {
localEngineLoaded = true;
}
}
и это ServletContextListener
:
@WebListener
final class YourServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
EmbeddedEngineHandler.markAsServletContext();
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
if (EmbeddedEngineHandler.isLocalEngineLoaded()) {
EmbeddedEngineHandler.unloadEmbeddedEngine();
}
}
}