【发布时间】:2011-08-22 07:22:24
【问题描述】:
我正在尝试将 Spring 集成到一个包含数千个类的相当大的应用程序中,但由于组件扫描,我在启动容器时遇到了巨大的延迟。
我已经将“base-package”中指定的目录数量缩小到最少,以减少扫描无关目录所浪费的时间,但是初始化的class-path扫描部分仍然需要大约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>");
}
}
编辑 2: Spring 5 包含一组重要的优化以加速上下文初始化,它还带有一个有趣且方便的功能,可以在编译时生成候选组件的索引: Spring Context Indexer
【问题讨论】:
-
目录中有多少(%)类是 Spring Bean?
-
我不太确定(这是一个非常大的项目),但我所看到的我相信它大约是 90% 到 100%,因为 xml 和属性文件被隔离在不同的位置)
-
呃,感觉你很痛苦。刚刚继承了一个具有 425 个配置 xml 的 3600 bean Spring 怪物。 9 分钟开机......在一个非常好的一天。谢谢你的帖子!手指交叉,将添加任何发现的金块。
-
你如何解决@Autowire 的问题?!
-
这再次证实了反射是一项非常昂贵的操作并且应该始终被缓存......或者它只是与 Spring 相关的反射?我们应该在哪里提交错误?甲骨文还是春天? ;-)
标签: java spring spring-mvc classpath bootstrapping