Skip to content

Grails demo app with large numbers of grails Domains and Services spring Beans, Configs

Notifications You must be signed in to change notification settings

rainboyan/grails-large-app-demo

Repository files navigation

Grails Large App Demo

Grails run-app development

grails create-app org.grails.demo.grails-large-app-demo
cd grails-large-app-demo
groovy gen_demo_class.groovy
grails run-app

Grails run war production

cd grails-large-app-demo
grails war
cd build/libs
java -jar grails-large-app-demo-0.1.war

Grails run app with spring Beans and Configs, use @ComponentScan

grails run-app

Performance Result

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

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

1000 Domains and Services

Grails 5.1.7 with 1000 Domains and Services

Domain & Services 5.1.7 5.1.8 (lazy-initialization: true)
1000 + 0 42500ms 40394ms
1000 + 1000 52758ms 48021ms

Plugin Loading Time

Loading plugins: 303ms Application Started: 7945ms

Domain & Services Plugin doWithSpring (475ms) doWithDynamicMethods (1ms) doWithApplicationContext (63ms)
0 + 0 restResponder 30ms 0ms 0ms
i18n 12ms 0ms 0ms
eventBus 6ms 0ms 0ms
core 17ms 0ms 0ms
codecs 0ms 0ms 0ms
dataSource 84ms 0ms 0ms
controllers 47ms 0ms 0ms
urlMappings 15ms 0ms 0ms
assetPipeline 43ms 0ms 0ms
groovyPages 83ms 0ms 0ms
scaffolding 2ms 0ms 0ms
mimeTypes 5ms 0ms 0ms
domainClass 9ms 0ms 0ms
controllersAsync 3ms 0ms 0ms
converters 13ms 0ms 0ms
hibernate 91ms 0ms 62ms
fields 6ms 0ms 0ms
interceptors 1ms 0ms 0ms
services 2ms 0ms 0ms
cache 5ms 0ms 1ms
Bean Class Time
convertersConfigurationInitializer org.grails.web.converters.configuration.ConvertersConfigurationInitializer 69ms
grailsPromiseFactory org.grails.async.factory.future.CachedThreadPoolPromiseFactory 17ms
grailsEventBus org.grails.events.bus.spring.EventBusFactoryBean 25ms
grailsEventBus org.grails.events.bus.ExecutorEventBus 25ms
requestMappingHandlerMapping org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping 28ms
requestMappingHandlerAdapter org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter 28ms
groovyMarkupConfigurer org.springframework.web.servlet.view.groovy.GroovyMarkupConfigurer 64ms
gspTagLibraryLookup org.grails.taglib.TagLibraryLookup 75ms
webEndpointServletHandlerMapping org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping 11ms

Loading plugins: 296ms Application Started: 50013ms

Domain & Services Plugin doWithSpring (4156ms) doWithDynamicMethods (1ms) doWithApplicationContext (77ms)
1000 + 1000 restResponder 13ms 0ms 0ms
i18n 11ms 0ms 0ms
eventBus 25ms 0ms 0ms
core 24ms 0ms 0ms
codecs 0ms 0ms 0ms
dataSource 90ms 0ms 0ms
controllers 42ms 0ms 0ms
urlMappings 15ms 0ms 0ms
assetPipeline 43ms 0ms 0ms
groovyPages 82ms 0ms 75ms
scaffolding 3ms 0ms 0ms
mimeTypes 8ms 0ms 0ms
domainClass 9ms 0ms 0ms
controllersAsync 4ms 1ms 0ms
converters 11ms 0ms 0ms
hibernate 3770ms ↑↑↑ 0ms 0ms
fields 4ms 0ms 0ms
interceptors 1ms 0ms 0ms
services 2ms 0ms 0ms
cache 6ms 0ms 1ms
Bean Class Time
annotationHandlerAdapter org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter 11ms
classPathFileSystemWatcher org.springframework.boot.devtools.classpath.ClassPathFileSystemWatcher 192ms ↑↑
convertersConfigurationInitializer org.grails.web.converters.configuration.ConvertersConfigurationInitializer 46ms
grailsPromiseFactory org.grails.async.factory.future.CachedThreadPoolPromiseFactory 15ms
grailsEventBus org.grails.events.bus.spring.EventBusFactoryBean 23ms
grailsEventBus org.grails.events.bus.ExecutorEventBus 23ms
groovyMarkupConfigurer org.springframework.web.servlet.view.groovy.GroovyMarkupConfigurer 57ms
gspTagLibraryLookup org.grails.taglib.TagLibraryLookup 76ms
requestMappingHandlerMapping org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping 32ms
requestMappingHandlerAdapter org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter 36ms
webEndpointServletHandlerMapping org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping 12ms
demo261DomainService org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean 19ms
demo54DomainService org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean 12ms
demo272DomainService org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean 12ms
demo668DomainService org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean 12ms
demo400DomainService org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean 13ms
demo683DomainService org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean 11ms
demo894DomainService org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean 11ms
demo979DomainService org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean 11ms
demo958DomainService org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean 13ms
demo554DomainService org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean 12ms
demo764DomainService org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean 13ms
demo500DomainService org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean 11ms
demo581DomainService org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean 11ms
demo675DomainService org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean 14ms
demo128DomainService org.grails.datastore.mapping.config.DatastoreServiceMethodInvokingFactoryBean 12ms

Todo

  • How to improve the performance of Spring Boot and Grails applications?

Related links

About

Grails demo app with large numbers of grails Domains and Services spring Beans, Configs

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published