How to monitor a Java EE DataSource
Are you struggling with performance issues in your Spring, Jakarta EE, or Java EE application?
What if there were a tool that could automatically detect what caused performance issues in your JPA and Hibernate data access layer?
Wouldn’t it be awesome to have such a tool to watch your application and prevent performance issues during development, long before they affect production systems?
Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, Micronaut, or Play Framework.
So, rather than fixing performance issues in your production system on a Saturday night, you are better off using Hypersistence Optimizer to help you prevent those issues so that you can spend your time on the things that you love!
Introduction
FlexyPool is an open-source framework that can monitor a DataSource connection usage. This tool come out of necessity, since we previously lacked support for provisioning connection pools.
FlexyPool was initially designed for stand-alone environments and the DataSource proxy configuration was done programmatically. Using Spring bean aliases, we could even substitute an already configured DataSource with the FlexyPool Metrics-aware proxy alternative.
Java EE support
Recently, I’ve been asked about supporting Java EE environments and in the true open-source spirit, I accepted the challenge. Supporting a managed environment is tricky because the DataSource is totally decoupled from the application-logic and made available through a JNDI lookup.
One drawback is that we can’t use automatic pool sizing strategies since most Application Servers return a custom DataSource implementation (which is closely integrated with their in-house JTA transaction manager solution), that doesn’t offer access to reading/writing the connection pool size.
While the DataSource might not be adjustable, we can at least monitor the connection usage and that’s enough reason to support Java EE environments too.
Adding declarative configuration
Because we operate in a managed environment, we can no longer configure the DataSource programmatically, so we need to use the declarative configuration support.
By default, FlexyPool looks for the flexy-pool.properties file in the current Class-path. The location can be customized using the flexy.pool.properties.path System property , which can be a:
- URL (e.g. file:/D:/wrk/vladmihalcea/flexy-pool/flexy-pool-core/target/test-classes/flexy-pool.properties)
- File system path (e.g. D:\wrk\vladmihalcea\flexy-pool\flexy-pool-core\target\test-classes\flexy-pool.properties)
- Class-path nested path (e.g. nested/fp.properties)
The properties file may contain the following configuration options:
| Parameter name | Description |
|---|---|
| flexy.pool.data.source.unique.name |
Each FlexyPool instance requires a unique name so that JMX domains won’t clash |
|
flexy.pool.data.source.jndi.name |
The JNDI DataSource location |
|
flexy.pool.data.source.jndi.lazy.lookup |
Whether to lookup the DataSource lazily (useful when the target DataSource is not available when the FlexyPoolDataSource is instantiated) |
|
flexy.pool.data.source.class.name |
The DataSource can be instantiated at Runtime using this Class name |
|
flexy.pool.data.source.property.* |
If the DataSource is instantiated at Runtime, each flexy.pool.data.source.property.${java-bean-property} will set the java-bean-property of the newly instantiated DataSource (e.g. flexy.pool.data.source.property.user=sa) |
|
flexy.pool.adapter.factory |
Specifies the PoolAdaptorFactory, in case the DataSource supports dynamic sizing. By default it uses the generic DataSourcePoolAdapter which doesn’t support auto-scaling |
|
flexy.pool.metrics.factory |
Specifies the MetricsFactory used for creating Metrics |
|
flexy.pool.metrics.reporter.log.millis |
Specifies the metrics log reported interval |
|
flexy.pool.metrics.reporter.jmx.enable |
Specifies if the jmx reporting should be enabled |
|
flexy.pool.metrics.reporter.jmx.auto.start |
Specifies if the jmx service should be auto-started (set this to true in Java EE environments) |
|
flexy.pool.strategies.factory.resolver |
Specifies a ConnectionAcquiringStrategyFactoryResolver class to be used for obtaining a list of ConnectionAcquiringStrategyFactory objects. This should be set only if the PoolAdaptor supports accessing the DataSource pool size. |
Instantiating the actual DataSource at runtime
When the application server starts, you need to have the FlexyPoolDataSource ready before the EntityManagerFactory finishes bootstrapping:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
⠀
<persistence-unit name="persistenceUnit" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
⠀
<jta-data-source>java:global/jdbc/flexypool</jta-data-source>
⠀
<properties>
<property
name="hibernate.hbm2ddl.auto"
value="update"/>
⠀
<property
name="hibernate.show_sql"
value="true"/>
⠀
<property
name="hibernate.dialect"
value="org.hibernate.dialect.HSQLDialect"/>
⠀
<property
name="hibernate.transaction.jta.platform"
value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform"/>
</properties>
</persistence-unit>
</persistence>
While in a production Java EE environment we use an Application server specific DataSource configuration, for simplicity sake, I’m going to configure the FlexyPooldataSource using the DataSourceDefinition annotation:
@DataSourceDefinition(
name = "java:global/jdbc/flexypool",
className = "com.vladmihalcea.flexypool.FlexyPoolDataSource")
@Stateless
public class FlexyPoolDataSourceConfiguration {}
We now need to pass the actual DataSource properties to FlexyPool and this is done through the flexy-pool.properties configuration file:
flexy.pool.data.source.unique.name=unique-name flexy.pool.data.source.class.name=org.hsqldb.jdbc.JDBCDataSource flexy.pool.data.source.property.user=sa flexy.pool.data.source.property.password= flexy.pool.data.source.property.url=jdbc:hsqldb:mem:test flexy.pool.metrics.reporter.jmx.auto.start=true
The actual DataSource is going to be created by the FlexyPoolDataSource on start-up.
Locating the actual DataSource from JNDI
If the actual DataSource is already configured by the Application Server, we can instruct FlexyPool to fetch it from JNDI. Let’s say we have the following DataSource configuration:
@DataSourceDefinition(
name = "java:global/jdbc/default",
className = "org.hsqldb.jdbc.JDBCDataSource",
url = "jdbc:hsqldb:mem:test",
initialPoolSize = 3,
maxPoolSize = 5
)
@Stateless
public class DefaultDataSourceConfiguration {}
To proxy the JNDI DataSource, we need to configure FlexyPool like this:
flexy.pool.data.source.unique.name=unique-name flexy.pool.data.source.jndi.name=java:global/jdbc/default flexy.pool.metrics.reporter.jmx.auto.start=true
The FlexyPoolDataSource is defined alongside the actual DataSource:
@DataSourceDefinition(
name = "java:global/jdbc/flexypool",
className = "com.vladmihalcea.flexypool.FlexyPoolDataSource")
@Stateless
public class FlexyPoolDataSourceConfiguration {}
The JPA will have to fetch the FlexyPoolDataSource instead of the actual one:
<jta-data-source>java:global/jdbc/flexypool</jta-data-source>
If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.
Conclusion
The last time I used Java EE was in 2008, on a project that was using Java EE 1.4 with EJB 2.1. After 7 years of using Spring exclusively, I’m pleasantly surprised by the Java EE experience. Arquillian is definitely my favorite add-on, since integration testing is of paramount importance in enterprise applications. CDI is both easy and powerful and I’m glad the dependency injection got standardized.
But the best asset of the Java EE platform is the community itself. Java EE has very strong community, willing to give you a hand when in need. I’d like to thank Steve Millidge (Founder of Payara and C2B2) for giving me some great tips on designing the FlexyPool Java EE integration, Alex Soto, Antonio Goncalves, Markus Eisele and all the other Java EE members whom I had some very interesting conversations on Twitter.






