Custom Spring Boot Actuator Endpoint
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
In this article, we are going to see how we can create a custom Spring Boot Actuator endpoint in order to export our own metrics and events.
Spring Boot Actuator is a Spring Boot module that provides support for tracing and monitoring. And, while by default, we get various health checks and metrics, we are not limited to the default implementation.
Spring Boot Actuator configuration
If your Spring Boot application is not using the Actuator module, then the first step is to add the following dependency to your pom.xml Maven configuration file:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
The next step is to instruct Spring Boot to expose all available metrics via the following setting that you need to add to your application.properties file:
management.endpoints.web.exposure.include=*
Adding a custom Spring Boot Actuator Endpoint
Now, assuming we have integrated Hypersistence Optimizer, which provides us with Java Persistence and Hibernate performance tuning tips, we would like to expose the tips via the Spring Boot actuator service.
So, we will need to create a custom endpoint that exports the Hypersistence Optimizer events via the web interface.
To create the custom Spring Boot Actuator endpoint, we are going to use the following Spring component:
@Component
@Endpoint(id = "hypersistence-optimizer")
public class HypersistenceOptimizerMetrics {
⠀
@PersistenceUnit
private EntityManagerFactory entityManagerFactory;
⠀
private HypersistenceOptimizer hypersistenceOptimizer;
⠀
@PostConstruct
public void init() {
hypersistenceOptimizer = new HypersistenceOptimizer(
new JpaConfig(entityManagerFactory)
);
}
⠀
@ReadOperation
public List<String> events() {
return hypersistenceOptimizer.getEvents()
.stream()
.map(Event::getDescription)
.toList();
}
}
The @Endpoint annotation allows us to define the path component where we will locate the custom Hypersistence Optimizer events.
The @ReadOperation annotation allows us to expose the Hypersistence Optimizer events.
Now, when visiting the /actuator/hypersistence-optimizer relative path, we will get the following response:
[ "The [id] identifier attribute in the [com.revogain.model.persistence.FailedTopUpOperation] entity uses the [IdentityGenerator] strategy, which prevents Hibernate from enabling JDBC batch inserts. Since the database does not support the SEQUENCE identifier strategy, you need to use plain JDBC or some other data access framework to batch insert statements.", "The [id] identifier attribute in the [com.revogain.model.persistence.BaseOperation] entity uses the [IdentityGenerator] strategy, which prevents Hibernate from enabling JDBC batch inserts. Since the database does not support the SEQUENCE identifier strategy, you need to use plain JDBC or some other data access framework to batch insert statements.", "The [id] identifier attribute in the [com.revogain.model.persistence.User] entity uses the [IdentityGenerator] strategy, which prevents Hibernate from enabling JDBC batch inserts. Since the database does not support the SEQUENCE identifier strategy, you need to use plain JDBC or some other data access framework to batch insert statements.", "The [id] identifier attribute in the [com.revogain.model.persistence.StatementParsingError] entity uses the [IdentityGenerator] strategy, which prevents Hibernate from enabling JDBC batch inserts. Since the database does not support the SEQUENCE identifier strategy, you need to use plain JDBC or some other data access framework to batch insert statements.", "The [id] identifier attribute in the [com.revogain.model.persistence.PasswordResetToken] entity uses the [IdentityGenerator] strategy, which prevents Hibernate from enabling JDBC batch inserts. Since the database does not support the SEQUENCE identifier strategy, you need to use plain JDBC or some other data access framework to batch insert statements.", "The [id] identifier attribute in the [com.revogain.model.persistence.Operation] entity uses the [IdentityGenerator] strategy, which prevents Hibernate from enabling JDBC batch inserts. Since the database does not support the SEQUENCE identifier strategy, you need to use plain JDBC or some other data access framework to batch insert statements.", "The [id] identifier attribute in the [com.revogain.model.persistence.StatementReportOperation] entity uses the [IdentityGenerator] strategy, which prevents Hibernate from enabling JDBC batch inserts. Since the database does not support the SEQUENCE identifier strategy, you need to use plain JDBC or some other data access framework to batch insert statements.", "The [id] identifier attribute in the [com.revogain.model.persistence.TopUpOperation] entity uses the [IdentityGenerator] strategy, which prevents Hibernate from enabling JDBC batch inserts. Since the database does not support the SEQUENCE identifier strategy, you need to use plain JDBC or some other data access framework to batch insert statements.", "Your application is using the [org.hibernate.dialect.MySQL57Dialect] Hibernate-specific Dialect. Consider using the [org.hibernate.dialect.MySQL8Dialect] instead, as it's closer to your current database server version [MySQL 8.0].", "If you set the [hibernate.jdbc.batch_size] configuration property to a value greater than 1 (usually between 5 and 30), Hibernate can then execute SQL statements in batches, therefore reducing the number of database network roundtrips.", "PostgreSQL can use multi-value inserts that can speed up batching as fewer statements must be executed by the database engine. To enable this feature set the [reWriteBatchedInserts] JDBC configuration property to the value of [true].", "You should set the [hibernate.query.fail_on_pagination_over_collection_fetch] configuration property to the value of [true], as Hibernate can then prevent in-memory pagination when join fetching a child entity collection.", "You should set the [hibernate.query.in_clause_parameter_padding] configuration property to the value of [true], as Hibernate entity queries can then make better use of statement caching and fewer entity queries will have to be compiled while varying the number of parameters passed to the in query clause.", "You should set the [hibernate.query.plan_cache_max_size] configuration property to a value that allows you to hold all JPQL, Criteria API, or SQL queries executed with Hibernate. The default query plan cache size is [2048] and might not be enough for a non-trivial application." ]
Awesome, right?
If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.
Conclusion
Spring Boot Actuator is a very useful addition to any non-trivial Spring application or service.
Not only does it provide a wide range of metrics, but we can even expose our own events via a custom Spring Boot Actuator endpoint.


