春季启动性能问题

问题描述 投票:37回答:6

[我试图将Spring集成到具有数千个类的大型应用程序中,由于进行组件扫描,我在启动容器时遇到了巨大的延迟。

我已经将“基本软件包”中指定的目录数量减少到最小,以减少扫描无关目录所浪费的时间,但是初始化的类路径扫描部分仍然需要大约1-2分钟。

因此,有没有一种方法可以优化扫描过程?我曾考虑过将候选类路径存储在文件中,然后使容器从文件中获取,而不是每次启动时都扫描类路径,但是我真的不知道从哪里开始,或者甚至可能。

任何建议都非常感谢。提前致谢。


Edit1:从一个自动生成的xml文件加载bean定义,将Spring引导时间减少到9〜10秒,这确认了Spring用于组件类路径扫描的反射API是启动延迟的主要来源。至于生成xml文件,这里是代码,因为它可能对遇到相同问题的人有所帮助。

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: Spring 5虽然包含了一组重要的优化来加速上下文初始化,但是它具有一个有趣且方便的功能,可以在编译时生成候选组件的索引:Spring Context Indexer] >

我正在尝试将Spring集成到具有数千个类的大型应用程序中,由于组件扫描,我在启动容器时遇到了巨大的延迟。我已经缩小了范围...

java spring spring-mvc classpath bootstrapping
6个回答
9
投票

问题:Spring Bean中的目录中有多少类(以百分比为单位)?


4
投票

自动发现带注释的类当前需要扫描指定包中的所有类,并且可能花费很长时间,这是当前类加载机制的已知问题。

Java 9将在此处帮助Jigsaw。


4
投票

您对那里的性能无能为力,我想您并不关心生产环境中的启动,而是测试的启动时间*。两个提示:

  • 审查您的测试应用程序上下文仅使用您应用程序的最低要求组件
  • 不是使用组件扫描指令的列表,而是使用一个带有逗号分隔值的指令,例如:base-package =“ com.package.one,com.package.two ...”

2
投票

除了减少要扫描的目录之外,我唯一想到的就是使用lazy bean initialization。如果您有很多豆,这可能会有所帮助


2
投票

您可以使用Spring的Java-based container configuration代替组件扫描。


2
投票

我知道这是一个老问题,您会看到当时的情况有所不同,但希望它可以像我一样帮助其他人研究此问题。

根据对另一个问题的答案,@ComponentScan注释现在支持lazyInit标志,这应有助于减少启动时间。

© www.soinside.com 2019 - 2024. All rights reserved.