Marco
Marco

Reputation: 607

Spring: detect lazy beans at runtime

Is there any way to detect wether a bean is lazily initialized that works reliably and for every bean in context?

In particular a bean such as this one:

@Configuration
class MyConfig() {

@Bean
@Lazy
Foo foo() {
  return new Foo();
}

I could not find any way to programmatically detect 'foo' is lazy.

Other kind of lazy beans such as this:

@Lazy
@Component
class Bar {
  ...
}

can be detected with something like:

boolean isLazy = applicationContext.findAnnotationOnBean(beanName, Lazy.class) != null

this is not reliable, it can produce false-positives, for example if a Bar bean is part of a configuration that initializes it eagerly.

Upvotes: 1

Views: 1706

Answers (1)

Szymon Stepniak
Szymon Stepniak

Reputation: 42184

You can use ConfigurableListableBeanFactory.getBeanDefinition(String name) to get BeanDefinition instance and call BeanDefinition.isLazyInit() to get information if following bean is initialized using lazy initialization. It works for both cases described by you - when @Lazy is used on class and on bean factory method. Take a look at following example that load prints out all beans that are loaded lazily:

import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;

@SpringBootApplication
public class Application {

    @Bean
    @Lazy
    public Foo foo() {
        return new Foo();
    }

    public static void main(String[] args) {
        final ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);

        ctx.getBeanFactory().getBeanNamesIterator().forEachRemaining(bean -> {
            try {
                final BeanDefinition beanDefinition = ctx.getBeanFactory().getBeanDefinition(bean);
                if (beanDefinition.isLazyInit()) {
                    System.out.println("Bean '" + bean + "' is lazy initialized...");
                }
            } catch (NoSuchBeanDefinitionException e) {}
        });
    }

    static class Foo {
        private boolean bar = true;
    }
}

When I run it I see following part in the console:

Bean 'otherLazyBean' is lazy initialized...
Bean 'foo' is lazy initialized...
Bean 'mvcHandlerMappingIntrospector' is lazy initialized...

This otherLazyBean is a component class annotated with @Lazy annotation. Hope it helps.

Upvotes: 2

Related Questions