Spring Load-Time Weaving

Imagine having a tool that can automatically detect JPA and Hibernate performance issues. Wouldn’t that be just awesome?

Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, or Play Framework.

So, enjoy spending your time on the things you love rather than fixing performance issues in your production system on a Saturday night!

Introduction

In this article, we are going to see how Spring load-time weaving works so that you can apply the Hibernate bytecode enhancement mechanism at runtime.

Traditionally, the bytecode enhancement mechanism is applied when the project is built using a Maven or Gradle plugin. For more details about the build-time approach, check out this article.

Domain Model

Let’s consider we have the following Attachment entity that has a content property that is mapped as follows:

@Lob
@Column(columnDefinition="BLOB")
@Basic(fetch = FetchType.LAZY)
private byte[] content;

The content property is using the FetchType.LAZY fetching strategy, but loading entity attributes lazily cannot be done on POJO entities, so we need the Hibernate bytecode enhancement mechanism to achieve this goal.

Hibernate Bytecode Enhancement Mechanism

The Hibernate bytecode enhancement mechanism allows us to change the bytecode of a JPA entity so that we can intercept the getter and the setter method calls in order to:

  • load attributes lazily
  • record entity modifications

Most often, the bytecode enhancement mechanism is configured via a Maven or Gradle plugin, which enhances the entity classes when the project is built, as explained in this article.

However, this is not the only approach we can use since we can also instrument the JPA entity classes at runtime when the project is bootstrapped.

Spring Data JPA Load-Time Weaving

To enable the runtime bytecode enhancement mechanism when bootstrapping a Spring application, you have to add the @EnableLoadTimeWeaving annotation to your Spring configuration:

@EnableLoadTimeWeaving
public class BytecodeEnhancementConfiguration {
    ...
}

Now, we need to provide the Spring Instrumentation library to the JVM via the javaagent argument. If you’re using Windows, you could do it like this:

-javaagent:%M2_REPOSITORY%\org\springframework\spring-instrument\%SPRING_VERSION%\spring-instrument-%SPRING_VERSION%.jar

That’s it!

Testing Time

When loading an Attachment entity and accessing the content property:

Attachment book = attachmentRepository.findById(1L).orElseThrow(null);

LOGGER.debug("Fetched book: {}", book.getName());

assertArrayEquals(readBytes(bookFilePath), book.getContent());

We can see that the content column is not fetched by the first SQL query, being fetched on demand in a secondary SQL query:

SELECT 
    a.id,
    a.media_type,
    a.name 
FROM 
    attachment a 
WHERE 
    a.id = 1

-- Fetched book: High-Performance Java Persistence

SELECT 
    a.content 
FROM 
    attachment a 
WHERE 
    a.id = 1

Awesome, right?

I'm running an online workshop on the 20-21 and 23-24 of November about High-Performance Java Persistence.

If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.

Conclusion

Using the Spring load-time weaving mechanism can be very useful if we want to enhance the JPA entity classes without having access to the project build.

The @EnableLoadTimeWeaving annotation tells Spring to register a LoadTimeWeaver bean that will be provided to the JPA EntityManagerFactory to enhance the JPA entities that get loaded, giving us the opportunity to enable the bytecode enhancement lazy loading or dirty tracking mechanisms.

Transactions and Concurrency Control eBook

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.