Class JpaServletContextListener
- java.lang.Object
-
- pl.morgwai.base.servlet.scopes.GuiceServletContextListener
-
- pl.morgwai.base.servlet.guiced.jpa.JpaServletContextListener
-
- All Implemented Interfaces:
ServletContextListener
,EventListener
- Direct Known Subclasses:
JpaPingingServletContextListener
public abstract class JpaServletContextListener extends GuiceServletContextListener
Manages the lifecycle ofthe main persistent unit
and its associatedexecutor
.A single subclass must be created and either annotated with
@WebListener
or enlisted inweb.xml
file inlistener
element.Components that perform JPA operations (such as DAOs) should request injection of
Provider
<EntityManager
> instances.
If the app uses multiple persistence units (whenisSinglePersistenceUnitApp()
is overridden to returnfalse
), each injection point must be additionally annotated with @Named
to indicate which persistence unit should be used. In such case,the main persistence unit
will be bound for injection with the nameMAIN_PERSISTENCE_UNIT_BINDING_NAME
.All JPA operations on the main persistence unit should be dispatched to
mainJpaExecutor
to avoid blocking server threads when waiting for an available JDBC connection.Components that need to create named queries as a part of their initialization can request injection of
EntityManagerFactory
(with @Named
if app uses multiple persistence units) and create 1 initialEntityManager
instance to createQuery
instances.
NOTE: this initialEntityManagerFactory
andEntityManager
instances MUST NOT be retained beyond named queries initialization. Subsequent JPA operations during normal application request processing should happen via properly scopedEntityManager
instances obtained from the injectedProvider
<EntityManager
>.
-
-
Field Summary
Fields Modifier and Type Field Description static String
JPA_EXECUTOR_NAME_SUFFIX
Appended to persistence unit name to create associated executor name.static String
MAIN_PERSISTENCE_UNIT_BINDING_NAME
Injection binding name forthe main persistence unit
associated objects in apps that use multiple persistence units.protected ContextTrackingExecutor
mainJpaExecutor
Executor associated withthe main persistence unit
.-
Fields inherited from class pl.morgwai.base.servlet.scopes.GuiceServletContextListener
log, servletContainer, servletModule, websocketContainer
-
-
Constructor Summary
Constructors Constructor Description JpaServletContextListener()
-
Method Summary
All Methods Instance Methods Abstract Methods Concrete Methods Modifier and Type Method Description void
contextDestroyed(ServletContextEvent event)
Shuts down the mainEntityManagerFactory
andmainJpaExecutor
.protected Injector
createInjector(LinkedList<Module> modules)
Creates injector with an additional module that binds injections ofEntityManagerFactory
,mainJpaExecutor
andEntityManager
s ofthe main persistence unit
.protected ContextTrackingExecutor
createJpaExecutor(String persistenceUnitName, int poolSize)
Creates an executor to be associated with a persistence unit.protected abstract int
getMainJpaThreadPoolSize()
Returns the size of the thread pool to be used bymainJpaExecutor
.protected abstract String
getMainPersistenceUnitName()
Returns the name of the main persistence unit inpersistence.xml
file.protected boolean
isSinglePersistenceUnitApp()
Indicates whether this app uses only 1 persistence unit.-
Methods inherited from class pl.morgwai.base.servlet.scopes.GuiceServletContextListener
addEndpoint, addEndpoint, addFilter, addFilter, addFilter, addServlet, configureInjections, configureServletsFiltersEndpoints, contextInitialized, getExecutorsShutdownTimeoutSeconds, getInjector
-
-
-
-
Field Detail
-
mainJpaExecutor
protected ContextTrackingExecutor mainJpaExecutor
Executor associated withthe main persistence unit
.All JPA operations on the main persistence unit should be dispatched to this executor to avoid blocking server threads when waiting for an available JDBC connection.
ThreadPool size of this executor is determined by
getMainJpaThreadPoolSize()
.A reference can be obtained by requesting injection of
ContextTrackingExecutor
. If the app uses multiple persistence units (isSinglePersistenceUnitApp()
is overridden to returnfalse
) then injection points must be annotated with@Named
similarly to the below:@Named(JpaServletContextListener.MAIN_PERSISTENCE_UNIT_BINDING_NAME)
-
JPA_EXECUTOR_NAME_SUFFIX
public static final String JPA_EXECUTOR_NAME_SUFFIX
Appended to persistence unit name to create associated executor name.
-
MAIN_PERSISTENCE_UNIT_BINDING_NAME
public static final String MAIN_PERSISTENCE_UNIT_BINDING_NAME
Injection binding name forthe main persistence unit
associated objects in apps that use multiple persistence units.If the app uses a single persistence unit (default,
isSinglePersistenceUnitApp()
is not overridden and returnstrue
) then this constant is never used.If
isSinglePersistenceUnitApp()
returnsfalse
, then this constant is used as the value ofNamed
annotation for injection bindings ofEntityManagerFactory
,mainJpaExecutor
andEntityManager
s associated withthe main persistence unit
.- See Also:
- Constant Field Values
-
-
Method Detail
-
getMainPersistenceUnitName
protected abstract String getMainPersistenceUnitName()
Returns the name of the main persistence unit inpersistence.xml
file.
-
getMainJpaThreadPoolSize
protected abstract int getMainJpaThreadPoolSize()
Returns the size of the thread pool to be used bymainJpaExecutor
.The value should be determined by load-testing and should not be simply the same as the size of the associated JDBC connection pool, as most JPA implementations perform read-only transactions purely in cache, without using a JDBC connection.
Setting the value too low will result in underutilization of the connection pool, while setting it too big will have no other impact than the cost of creating the threads, which is usually negligible on 64bit machines.
-
createJpaExecutor
protected ContextTrackingExecutor createJpaExecutor(String persistenceUnitName, int poolSize)
Creates an executor to be associated with a persistence unit. Used to createmainJpaExecutor
. Subclasses may override this method to customize executor creation. By default returnsservletModule.newContextTrackingExecutor( persistenceUnitName + JPA_EXECUTOR_NAME_SUFFIX, poolSize);
-
isSinglePersistenceUnitApp
protected boolean isSinglePersistenceUnitApp()
Indicates whether this app uses only 1 persistence unit. By defaulttrue
.If
true
thenEntityManager
instances,EntityManagerFactory
and its associatedmainJpaExecutor
injections are bound without names, so that user-defined components don't need to annotate injected fields/params with@Named(JpaServletContextListener.MAIN_PERSISTENCE_UNIT_BINDING_NAME)
when there's only 1 choice.Apps that use multiple persistence units should create a separate injection binding name constant and a separate
ContextTrackingExecutor
instance for each persistence unit. Each executor's threadPool size should correspond to the connection pool size of its persistence unit.
After that, given persistence unit'sEntityManagerFactory
, executor andEntityManager
should be bound with the corresponding constant as the value of@Named
inGuiceServletContextListener.configureInjections()
similarly to the below:@Override protected boolean isSinglePersistenceUnitApp() { return false; } public static final String CHAT_LOG_NAME = "chatLogDb"; // same as in persistence.xml public static final int CHAT_LOG_POOL_SIZE = 10; EntityManagerFactory chatLogEntityManagerFactory; ContextTrackingExecutor chatLogJpaExecutor; @Override protected LinkedList
configureInjections() { chatLogEntityManagerFactory = Persistence.createEntityManagerFactory(CHAT_LOG_NAME); chatLogJpaExecutor = createJpaExecutor(CHAT_LOG_NAME, CHAT_LOG_POOL_SIZE); var modules = new LinkedList (); modules.add((binder) -> { binder.bind(EntityManager.class) .annotatedWith(Names.named(CHAT_LOG_NAME)) .toProvider(() -> chatLogEntityManagerFactory.createEntityManager()) .in(servletModule.containerCallScope); binder.bind(EntityManagerFactory.class) .annotatedWith(Names.named(CHAT_LOG_NAME)) .toInstance(chatLogEntityManagerFactory); binder.bind(ContextTrackingExecutor.class) .annotatedWith(Names.named(CHAT_LOG_NAME)) .toInstance(chatLogJpaExecutor); }); // more modules here... } @Override public void contextDestroyed(ServletContextEvent event) { // user components shutdowns here... super.contextDestroyed(event); chatLogEntityManagerFactory.close(); }
-
createInjector
protected Injector createInjector(LinkedList<Module> modules)
Creates injector with an additional module that binds injections ofEntityManagerFactory
,mainJpaExecutor
andEntityManager
s ofthe main persistence unit
.- Overrides:
createInjector
in classGuiceServletContextListener
-
contextDestroyed
public void contextDestroyed(ServletContextEvent event)
Shuts down the mainEntityManagerFactory
andmainJpaExecutor
.- Specified by:
contextDestroyed
in interfaceServletContextListener
- Overrides:
contextDestroyed
in classGuiceServletContextListener
-
-