Spring-framework: Evaluate "clever" lazy bean initialization

Created on 11 Mar 2019  路  8Comments  路  Source: spring-projects/spring-framework

This proposal intend to make Spring applications startup time and memory consumption stable regardless of the amount of user classes and beans.

The idea would be to use compile-time indexing of annotations like @RequestMapping (and others) to avoid (when lazy loading is activated) loading transitively all the classes of the application "just" to scan annotations on beans like the mapping ones.

One solution could be to improve spring-context-indexer to index annotations (like handler methods mappings) at compile time and make this data available in META-INF. That would allow methods like AbstractHandlerMethodMapping#initHandlerMethods avoiding to load all classes at startup.

enhancement

Most helpful comment

I tend to think that if we improve this feature to load eagerly only infrastructure beans (we could use BeanDefinition.ROLE_INFRASTRUCTURE as a flag) but keep most user beans lazy (for example those without initialization logic), we could maybe enable this on Spring Boot out of the box.

I'm not a great fan of switching on lazy loading by default, even if we're smarter about which parts are eager and which are lazy. I feel like you're ultimately just paying initialization costs on the first request. If you're in a situation where you're scaling up application instances, I think it's probably better to wait until the app is fully initialized before sending traffic to it. With lazy loading, you're potentially giving some of your users a really bad experience.

All 8 comments

As suggested by @snicoll, this issue concerns more Spring Framework than Spring Boot and should be probably discussed and evaluated in https://github.com/spring-projects/spring-framework.

I tend to think that if we improve this feature to load eagerly only infrastructure beans (we could use BeanDefinition.ROLE_INFRASTRUCTURE as a flag) but keep most user beans lazy (for example those without initialization logic), we could maybe enable this on Spring Boot out of the box.

I'm not a great fan of switching on lazy loading by default, even if we're smarter about which parts are eager and which are lazy. I feel like you're ultimately just paying initialization costs on the first request. If you're in a situation where you're scaling up application instances, I think it's probably better to wait until the app is fully initialized before sending traffic to it. With lazy loading, you're potentially giving some of your users a really bad experience.

Point taken, we should maybe not enable that by default. But I still think we could explore ways we have to stop considering classes and beans as a monolithic set fully loaded as startup and consuming more resource as the application grow, and explore more the ways we have to keep performances stable as the application grow.

Unrelated note: @rstoyanchev first feedback is that we should probably evaluate such mechanism globally, not only for handler methods mapping.

Here's an interesting data point. In https://github.com/spring-projects/spring-data-examples there is a starbucks sample (Mongodb with a custom bean that initializes the database). When you switch on lazy beans using spring.main.lazy-initialization the database is never initialized because the initializer is not a dependency of anything and it is lazy. You can make it initialize on first HTTP request by hacking a dependency between the handler mapping and the initializer:

@Component
class DependencyTweak implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
            throws BeansException {
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
            throws BeansException {
        if (registry.containsBeanDefinition("requestMappingHandlerMapping")) {
            BeanDefinition bd = registry
                    .getBeanDefinition("requestMappingHandlerMapping");
            bd.setDependsOn("storeInitializer");
        }
    }

}

This is probably not a solution we should recommend to users, but it shows what is possible. Maybe we need a special contract for such use cases - an application event for the first request for instance.

Cc: @odrotbohm .

i think @EventListener(ApplicationReadyEvent.class) correctly gives even lazy beans a chance to register side-effects eagerly, even if nothing else depends on them?

I have updated the description of this issue to make it (hopefully) more understandable and more focused on Spring Framework scope, without any assumption of what should be the default lazy loading behavior on Spring Boot side.

i think @EventListener(ApplicationReadyEvent.class) correctly gives even lazy beans a chance to register side-effects eagerly, even if nothing else depends on them?

That would still initialize the downstream dependencies on startup, which might be just fine as that initializes exactly only the tree of dependencies that are needed to execute the initializing functionality. For the Spring Data example that Dave and I were discussing we were wondering if there was a way to sort of trigger the same functionality on first request. I think both ways are reasonable use cases.

We have discussed that during Spring Framework meeting, and the feedback is that there are at least 2 points that makes it very difficult to achieve:

  • The time and memory required to parse the index will likely annihilate the performance gain for small and middle sized applications
  • The class tree is mostly loaded in any case during context refresh phase.

I close this issue for now since these 2 limitations seems blocking to me, feel free to comment in case of new findings.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

spring-projects-issues picture spring-projects-issues  路  5Comments

sbrannen picture sbrannen  路  4Comments

davidjgoss picture davidjgoss  路  4Comments

imochurad picture imochurad  路  4Comments

AstralStorm picture AstralStorm  路  4Comments