Tuesday, February 4, 2020

Spring Boot: Lazy Init Configuration Example


Make your Spring Boot app start faster using LazyInitConfiguration and implement with BeanFactoryPostProcessor.

@Configuration
public class LazyInitConfiguration implements BeanFactoryPostProcessor {
   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
      for (String beanName : beanFactory.getBeanDefinitionNames()) {
         beanFactory.getBeanDefinition(beanName).setLazyInit(true);
      }
   }
}

Spring Boot introduces the spring.main.lazy-initialization property, making it easier to configure lazy initialization across the whole application.

Setting the property value to true means that all the beans in the application will use lazy initialization.

Let's configure the property in our application.yml configuration file:
spring:
  main:
    lazy-initialization: true

Or, if it's the case, in our application.properties file:
spring.main.lazy-initialization=true

This configuration affects all the beans in the context. So, if we want to configure lazy initialization for a specific bean, we can do it through the @Lazy approach.

Even more, we can use the new property, in combination with the @Lazy annotation, set to false.
Or in other words, all the defined beans will use lazy initialization, except for those that we explicitly configure with @Lazy(false).

Here's the result. It became just a little bit faster.
Benchmark                                          Mode  Cnt  Score   Error  Units
MyBenchmark.case01_FluxBaseline                      ss   10  2.938 ± 0.287   s/op
MyBenchmark.case02_WithLazyInit                      ss   10  2.844 ± 0.129   s/op

Reference:

Monday, October 28, 2019

Hibernate Lazy Load No Transaction Example


Introduction

I’ve already written about the Open Session in View Anti-Pattern, so now it’s time to add another Hibernate fetching bad practices. Although the hibernate.enable_lazy_load_no_trans configuration property is a lesser-known setting, it’s good to know why you shouldn’t employ it in your data access layer code.

What does it do?

By default, this property is disabled and, to enable it, you need to provide the following configuration property:
1
2
3
<property
    name="hibernate.enable_lazy_load_no_trans"
    value="true"/>
Considering the following entities:

With this configuration property in place, the following code snippets can be executed without throwing any LazyInitializationException:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
List<PostComment> comments = null;
EntityManager entityManager = null;
EntityTransaction transaction = null;
try {
    entityManager = entityManagerFactory()
        .createEntityManager();
    transaction = entityManager.getTransaction();
    transaction.begin();
    comments = entityManager.createQuery(
        "select pc " +
        "from PostComment pc " +
        "where pc.review = :review", PostComment.class)
    .setParameter("review", review)
    .getResultList();
    transaction.commit();
catch (Throwable e) {
    if ( transaction != null && transaction.isActive())
        transaction.rollback();
    throw e;
finally {
    if (entityManager != null) {
        entityManager.close();
    }
}
for(PostComment comment : comments) {
    LOGGER.info("The post title is '{}'",
        comment.getPost().getTitle());
}
Without the hibernate.enable_lazy_load_no_trans configuration property in place, the comment.getPost().getTitle() line would throw a LazyInitializationException because the comments collection was not initialized, and the Persistence Context is already closed, along with the database connection that fetched the post entity.
Behind the scenes, a temporary Session is opened just for initializing every post association. Every temporary Session implies acquiring a new database connection, as well as a new database transaction.
The more association being loaded lazily, the more additional connections are going to be requested which puts pressure on the underlying connection pool. Each association being loaded in a new transaction, the transaction log is forced to flush after each association initialization.
Reference: