How to debug connection pool configurations with springboot?
1. The purpose of this post
Sometimes, you may want to know what connection pool you are using with Spring Boot. This demo shows how to debug the connection pooling configurations when using Spring Boot applications. It’s very easy to do this job—let’s get started.
2. Environments
- Spring Boot 1.x and 2.x
- Java 1.8+
3. The solution
3.1 Add AspectJ to your POM.xml
To inspect the datasource configurations, we will use the Spring AOP solution. It depends on these artifacts:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId></dependency><dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.12</version></dependency>
To demonstrate different connection pooling configurations, we add this connection pool implementation as follows:
<dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>3.2.0</version></dependency>
3.2 Write an aspect to intercept the process
Suppose we have a DAO class com.sb1jt.dao.CityDao
like this:
package com.sb1jt.dao;
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Component;
@Componentpublic class CityDao { @Autowired private JdbcTemplate jdbcTemplate;
public City getCity(Integer id) { // Call jdbcTemplate here }}
We must write an aspect to intercept the datasource calling process like this:
import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Aspect@Configurationpublic class ConnectionAspect { private static Logger logger = LoggerFactory.getLogger(ConnectionAspect.class);
@Autowired private DataSource ds;
@Before("execution(* com.sb1jt.dao.*.*(..))") public void logBeforeConnection(JoinPoint jp) throws Throwable { if (ds instanceof org.apache.tomcat.jdbc.pool.DataSource) { // Default connection pool of Spring Boot 1.x org.apache.tomcat.jdbc.pool.DataSource tomcatDs = (org.apache.tomcat.jdbc.pool.DataSource) ds; logger.info("Datasource props: {}", tomcatDs.getPoolProperties()); } else if (ds instanceof com.zaxxer.hikari.HikariDataSource) { // Default connection pool of Spring Boot 2.x com.zaxxer.hikari.HikariDataSource hikariDs = (com.zaxxer.hikari.HikariDataSource) ds; logger.info("Datasource props: {}", hikariDs.getDataSourceProperties()); } }
@After("execution(* com.sb1jt.dao.*.*(..))") public void logAfterConnection(JoinPoint jp) throws Throwable { String methodName = jp.getTarget().getClass().getName() + ":" + jp.getSignature().getName();
if (ds instanceof org.apache.tomcat.jdbc.pool.DataSource) { org.apache.tomcat.jdbc.pool.DataSource tomcatDs = (org.apache.tomcat.jdbc.pool.DataSource) ds; logger.info("After method call: " + methodName + " : number of connections in use by the application (active): " + tomcatDs.getNumActive()); logger.info("After method call: " + methodName + " : the number of established but idle connections: " + tomcatDs.getNumIdle()); logger.info("After method call: " + methodName + " : number of threads waiting for a connection: " + tomcatDs.getWaitCount()); } else if (ds instanceof com.zaxxer.hikari.HikariDataSource) { com.zaxxer.hikari.HikariDataSource hikariDs = (com.zaxxer.hikari.HikariDataSource) ds; logger.info("Other props: {}", hikariDs.getDataSourceProperties()); } }}
3.3 Run the code
When you run the code, you will get output similar to this:
2019-05-12 16:12:08.357 INFO 14842 --- [nio-8080-exec-1] c.sb1jt.config.ConnectionAspect : ds type: org.apache.tomcat.jdbc.pool.DataSource2019-05-12 16:12:08.767 INFO 14842 --- [nio-8080-exec-1] c.sb1jt.config.ConnectionAspect : other props: ConnectionPool[defaultAutoCommit=true; defaultReadOnly=null; defaultTransactionIsolation=-1; defaultCatalog=null; driverClassName=com.mysql.jdbc.Driver; maxActive=30; maxIdle=2; minIdle=1; initialSize=9; maxWait=20000; testOnBorrow=true; testOnReturn=false; timeBetweenEvictionRunsMillis=5000; numTestsPerEvictionRun=0; minEvictableIdleTimeMillis=60000; testWhileIdle=false; testOnConnect=true; password=********; url=jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8; username=root; validationQuery=SELECT 1; validationQueryTimeout=5000; validatorClassName=null; validationInterval=3000; accessToUnderlyingConnectionAllowed=true; removeAbandoned=false; removeAbandonedTimeout=60; logAbandoned=false; connectionProperties=null; initSQL=null; jdbcInterceptors=null; jmxEnabled=true; fairQueue=true; useEquals=true; abandonWhenPercentageFull=0; maxAge=0; useLock=false; dataSource=null; dataSourceJNDI=null; suspectTimeout=0; alternateUsernameAllowed=false; commitOnReturn=false; rollbackOnReturn=false; useDisposableConnectionFacade=true; logValidationErrors=false; propagateInterruptState=false; ignoreExceptionOnPreLoad=false; useStatementFacade=true;2019-05-12 16:12:08.801 INFO 14842 --- [nio-8080-exec-1] c.sb1jt.config.ConnectionAspect : after method call : com.sb1jt.dao.CityDao:listCities : number of connections in use by the application (active) : 02019-05-12 16:12:08.802 INFO 14842 --- [nio-8080-exec-1] c.sb1jt.config.ConnectionAspect : after method call : com.sb1jt.dao.CityDao:listCities : the number of established but idle connections : 92019-05-12 16:12:08.802 INFO 14842 --- [nio-8080-exec-1] c.sb1jt.config.ConnectionAspect : after method call : com.sb1jt.dao.CityDao:listCities : number of threads waiting for a connection : 0
4. Conclusion
As demonstrated, you can write an aspect to intercept the DAO calling process. Before and after the method call, you can view the datasource’s connection pooling configurations. This approach is particularly useful for debugging and optimizing connection pool settings in Spring Boot applications.
5. Summary
In this post, we explored how to debug connection pool configurations in Spring Boot applications using AspectJ. By adding the necessary dependencies and writing an aspect, you can intercept and log connection pool details before and after method calls. This technique is invaluable for understanding and optimizing your application’s connection pool behavior.
Final Words + More Resources
My intention with this article was to help others who might be considering solving such a problem. So I hope that’s been the case here. If you still have any questions, don’t hesitate to ask me by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!