Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring startup performance issues

I'm trying to integrate Spring in a pretty large application with thousands of classes, and i'm experiencing huge delays starting my container because of component-scanning.

I have already narrowed the number of directories specified in the "base-package", to the minimum in order to reduce the time wasted in scanning irrelevant directories, but the class-path scanning part of initialization still takes about 1-2 mins.

So, is there a way to optimize the scanning process ? I've thought of storing the candidate classes path in a file and make the container then get them from the file instead of scanning the class-path with every startup, but i don't really know where to start or if that is even possible.

Any advice is much appreciated. Thanks in advance.


Edit1: Loading bean definitions form an autogenerated xml file, reduced the Spring bootstrap time to 9~10 secs which confirms that the reflection api used by Spring for the components class-path scanning is the major source of startup delays.
As for generating the xml file here is the code, since it might be helpful for someone with the same issues.

import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.util.ArrayList;   public class ConfigurationWriter {      public ArrayList<String> beanDefinitions = new ArrayList<String>();      public ConfigurationWriter() {          // the context loaded with old fashioned way (classpath scanning)         ApplicationContext context = SpringContainerServiceImpl.getInstance().getContext();         String[] tab = context.getBeanDefinitionNames();         for (int i = 0; i < tab.length - 6; i++) {             Class clazz = context.getType(tab[i]);             String scope = context.isPrototype(tab[i]) ? "prototype" : "singleton";             String s = "<bean id=\"" + tab[i] + "\" class=\"" + clazz.getName() + "\" scope=\"" + scope + "\"/>";             beanDefinitions.add(s);         }         // Collections.addAll(beanDefinitions, tab);      }      @SuppressWarnings("restriction")     public void generateConfiguration() throws FileNotFoundException {         File xmlConfig = new File("D:\\dev\\svn\\...\\...\\src\\test\\resources\\springBoost.xml");         PrintWriter printer = new PrintWriter(xmlConfig);          generateHeader(printer);          generateCorpse(printer);          generateTail(printer);          printer.checkError();      }      @SuppressWarnings("restriction")     private void generateCorpse(PrintWriter printer) {          for (String beanPath : beanDefinitions) {             printer.println(beanPath);         }      }      @SuppressWarnings("restriction")     private void generateHeader(PrintWriter printer) {         printer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");         printer.println("<beans xmlns=\"http://www.springframework.org/schema/beans\"");         printer.println("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");         printer.println("xmlns:context=\"http://www.springframework.org/schema/context\"");         printer.println("xsi:schemaLocation=\"");         printer.println("http://www.springframework.org/schema/mvc");         printer.println("http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd");         printer.println("http://www.springframework.org/schema/beans");         printer.println("http://www.springframework.org/schema/beans/spring-beans-3.0.xsd");         printer.println("http://www.springframework.org/schema/context");         printer.println("http://www.springframework.org/schema/context/spring-context-3.0.xsd\"");         printer.println("default-lazy-init=\"true\">");     }      @SuppressWarnings("restriction")     private void generateTail(PrintWriter printer) {         // printer.println("<bean class=\"com.xxx.frmwrk.spring.processors.xxxBeanFactoryPostProcessor\"/>");         printer.println("<bean class=\"com.xxx.frmwrk.spring.processors.xxxPostProcessor\"/>");         printer.println("</beans>");     }  } 

Edit 2: With Spring 5 including an important set of optimizations for speeding up the context initialization, It also comes with an interesting and handy feature that enables generating an index of candidate components at compile time : Spring Context Indexer

like image 391
Ben Avatar asked May 10 '11 09:05

Ben


People also ask

Why is Spring Boot so slow?

When a Spring Boot Application has slow startup, it can be one or more beans and related dependencies taking longer to initialise and slowing down the entire process. Profiling Spring Boot application doesn't often help in diagnosing the startup issues.

What are the disadvantages of Spring Boot?

Disadvantages of Spring BootLarge deployment files that result from unused dependencies. The long amount of time that it takes to replace legacy systems with Spring Boot applications. Its inability to build large, monolithic applications (although it works extremely well for developing microservices)

Why is Spring Boot faster?

Spring Native Native image is Java code compiled using an ahead-of-time compiler and packed into an executable file. It doesn't require Java to run. The resulting program is faster and less memory-dependent since there is no JVM overhead. The GraalVM project introduced native images and required build tools.


1 Answers

Question: How many (in %) of the classes in the directories are Spring Beans?

Answer: I'm not really sure (it's a really big project) , but from what i saw i believe it's arround 90 to 100%, since xml and properties files are isolated in separate locations)

If the problem is really the component scan and not the bean initializing process itself (and I highly doubt that), then the only solution I can imagine is to use Spring XML configuration instead of component scan. - (May you can create the XML file automatically).

But if you have many classes and 90% - 100% of them are Beans, then, the reduction of scanned files will have a maximal improvement of 10%-0%.

You should try other ways to speed up your initialization, may using lazy loading or any lazy loading related techniques, or (and that is not a joke) use faster hardware (if it is not a stand alone application).


A easy way to generate the Spring XML is to write a simple spring application that uses the class path scanning like your original application. After all Beans are initialize, it iterates through the Beans in the Spring Context, check if the bean belongs to the important package and write the XML Config for this bean in a file.

like image 122
Ralph Avatar answered Sep 23 '22 06:09

Ralph