Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance Improvement: Enable Lazy Initialization #12500

Closed
rainboyan opened this issue May 5, 2022 · 1 comment
Closed

Performance Improvement: Enable Lazy Initialization #12500

rainboyan opened this issue May 5, 2022 · 1 comment

Comments

@rainboyan
Copy link
Contributor

rainboyan commented May 5, 2022

Spring Boot 2.2 M1, Provide a configuration option to enable lazy initialisation

https://spring.io/blog/2019/03/14/lazy-initialization-in-spring-boot-2-2

It’s possible to enable lazy initialization in any version of Spring Boot if you’re happy to get your hands dirty and write a BeanFactoryPostProcessor. Spring Boot 2.2 just makes it easier via the introduction of a new property, spring.main.lazy-initialization (there are also equivalent methods on both SpringApplication and SpringApplicationBuilder). When set to true, bean definitions in the application will be configured to use lazy initialization.

Currently, Grails 5 support lazy initialization like this,

        gspTagLibraryLookup(TagLibraryLookup) { bean ->
            bean.lazyInit = true
        }

In Grails, if not set lazyInit, the BeanDefinition.isLazyInit() will be false default.

We can't config spring.main.lazy-initialization to enable global lazy initialization.

In Spring Boot LazyInitializationBeanFactoryPostProcessor, this PostProcessor will set LazyInit true if getLazyInit() was null, but Grails always set false.

	private void postProcess(ConfigurableListableBeanFactory beanFactory,
			Collection<LazyInitializationExcludeFilter> filters, String beanName,
			AbstractBeanDefinition beanDefinition) {
		Boolean lazyInit = beanDefinition.getLazyInit();
		if (lazyInit != null) {
			return;
		}
		Class<?> beanType = getBeanType(beanFactory, beanName);
		if (!isExcluded(filters, beanName, beanDefinition, beanType)) {
			beanDefinition.setLazyInit(true);
		}
	}

I create a large Grails app which has 2000 Beans, and I configure them in conf/spring/resources.groovy,

then, I test it on my old MacBook,

  • Mac OS 10.14.6, later 2013 8G RAM
  • Grails 5.1.7
  • Java 11.0.14-zulu
Bean & Config resources.groovy lazy-initialization: true lazy-initialization: false
0 + 0 7606ms 6478ms 7146ms
2000 + 0 18614ms 17251ms 17704ms

Also I edit the Grails source code, to enable lazy initialization like Spring Boot 2.2,


    protected AbstractBeanDefinition createBeanDefinition() {
        AbstractBeanDefinition bd = new GenericBeanDefinition();
...
        if(clazz != null) {
             // bd.setLazyInit( clazz.getAnnotation(Lazy.class) != null);
             if (clazz.getAnnotation(Lazy.class) != null) {
                 bd.setLazyInit(true);
             }
             bd.setBeanClass(clazz);
         }
...
        return bd;
    }

the test result was below, it's better than previous version.

Bean & Config resources.groovy lazy-initialization: true lazy-initialization: false
0 + 0 6243ms (18% ↓) 5862ms (23% ↓)
2000 + 0 18885ms 14423ms (24% ↓) 18462ms
@rainboyan
Copy link
Contributor Author

If I create 2000 DemoConfig to configure 2000 DemoBean, and enable @ComponentScan to scan all configs.

@CompileStatic
@ComponentScan
class Application extends GrailsAutoConfiguration { 
    static void main(String[] args) {
        GrailsApp.run(Application, args)
    }
}

The result is better than use Grails BeanBuilder configure in resources.groovy.

Bean & Config @componentscan lazy-initialization: true lazy-initialization: false
0 + 0 7606ms
2000 + 2000 25235ms 11809ms (53% ↓↓) 21468ms

more than that, if I add @Configuration(proxyBeanMethods = false) to all DemoConfig, the start time will be greatly reduced. It's only 9809ms (61% ↓↓↓) .

@Configuration(proxyBeanMethods = false)
public class Demo1000Config {
       @Bean
       public Demo1000Bean demo1000Bean() {
           return new Demo1000Bean("Demo 1000");
       }
}
Bean & Config @componentscan lazy-initialization: true lazy-initialization: false
0 + 0 7606ms
2000 + 2000 15889ms 9809ms (61% ↓↓↓) 16857ms

@rainboyan rainboyan closed this as not planned Won't fix, can't repro, duplicate, stale Oct 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants