Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Lazy load all the Spring beans whether it is defined by @Bean or @Component in Springboot 2.2

I am writing a spring application which is interactive and basically handles lots of commands like create, list, update, delete various types of resources.

For now, just assume a single run of the application handles only a single command and the program exits.

For all the classes to validate command, execute the command, required factory classes for each resource there is a separate class and each class is annotated with @Component annotation for spring to manage all the components.

There are also some of the manually defined beans by @Bean method.

Now that my application first identifies what kind of command is executed (create, delete, list, update, etc), I want the only beans of that command to be created and Autowired wherever required (after taking command from user) and I want to avoid the creation of dozens of beans related to other commands.

On searching, I came to know about Lazy instantiation of Beans that spring provides. However, I am not sure if it is the weapon I am searching for.

What I tried

  • Very first I found @Lazy annotation, but since I want to lazily load all the Beans, I don't want to write @Lazy everywhere in each class.
  • Then I found setting below property in application.yml does the work.
spring:
  main:
    lazy-initialization: true

I tried that but still, it is not lazily creating the beans.

My application.yml files looks like this

spring:
  main:
    lazy-initialization: true

My main SpringBootApplication file looks like this:

@Slf4j
@SpringBootApplication
public class SpringBootApplication {
    public static void main(String[] args) {
        System.out.println("Loading Application...");
        ApplicationContext context = SpringApplication.run(SpringBootApplication.class, args);



        final AtomicInteger counter = new AtomicInteger(0);
        log.info("**************** START: Total Bean Objects: {} ******************", context.getBeanDefinitionCount());

        Arrays.asList(context.getBeanDefinitionNames())
                .forEach(beanName -> {
                    log.info("{}) Bean Name: {} ", counter.incrementAndGet(), beanName);
                });

        log.info("**************** END: Total Bean: {} ******************", context.getBeanDefinitionCount());
    }
}

My other classes looks like this:


@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MyClass1 implements ResourceCreator<MyClass2, MyClass3> {
    private final RequestValidatorImpl requestValidator;
    private final ResourceCreator resourceCreator;

@Override
public MyClass2 toImplementFunction(MyClass3 myclass3) {
//logic
}

On running the application, It prints all the classes where I annotated @Component as well as beans created by @Bean method.

I have also tried using below in Application.properties but still no use.

spring.main.lazy-initialization=true

Also, if you wish, please comment on whether I should use @Component for each Class like I am using or not and what is better practice instead.

like image 212
CodeTalker Avatar asked Oct 25 '25 05:10

CodeTalker


1 Answers

I think you misunderstood the meaning of the lazy flag you are passing, It means that the object will be created only when it is invoked but it does not say that it will not scan that package. Spring will scan all packages and store bean definition names but it will create the objects only when it is invoked, if you have passed the lazy flag to it.

You can verify this behaviour by checking the number of beans created when you pass the lazy flag as true and false. you can check it as given below

ApplicationContext context = SpringApplication.run(SpringBootApplication.class, args);
System.out.println("count:"+context.getBeanDefinitionCount());

Edit on Apr/7th 2020 start

Another way to do that is create a constructor and use that to inject the autowired properties and print out a log when they enter the constructor.

I did the same in a sample project and below is he result, first one is for eager initialization and next one for lazy.

spring.main.lazy-initialization=false Application logs

Inside Constructor
calling bean
inside bean method

spring.main.lazy-initialization=true Application logs

calling bean
Inside Constructor
inside bean method

Edit on Apr/7th 2020 end

Please mark this as answered if I answered your question. Thank you

like image 185
Nithin Avatar answered Oct 26 '25 17:10

Nithin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!