按类型划分的弹簧布线在数量级上比按名称划分的布线慢

在我的项目中,我正在尝试迁移

Foo foo = (Foo) beanFactory.getBean("name");

Foo foo = beanFactory.getBean(Foo.class);

好处是显而易见的:类型安全,更少的复杂代码,更少的无用常量等。通常,此类线路位于静态传统环境中,其中此类布线是唯一的选择。

这一切都很好,直到有一天用户开始抱怨Spring内部的缓慢。因此,我启动了一个分析器来查找热点

org.springframework.beans.factory.support.AbstractBeanFactory::doGetBean(String, Class<T>, Object[], boolean)

它有一个昂贵的调用

Class.isAssignableFrom(anotherClass).

我快速创建了一个小的性能测试,以找出字符串名称和类型查找之间的速度差是350次(我用于此测试FAIW)!StaticApplicationContext

在调查这个问题时,我发现SPR-6870的票数很高,但由于某种原因没有得到解决。这导致我试图解决这个问题,这确实显着改善了这种情况,但仍然比String的查找慢25倍!事实证明,这种尝试只能解决一半的问题:它缓存bean的名称以保存在O(n)迭代中,但仍然需要执行调用来验证类型。isAssignableFrom

所描述的问题不仅与我的场景有关,而且还与使用bean有关,并且在循环中创建bean的情况下可能会感到困难。@Autowired

其中一个解决方案是覆盖其中一个bean工厂方法并缓存同类型的bean检查结果,但显然这应该在Spring中完成,而不是在我自己的代码中完成。

是否有其他人遭受类似的问题并找到了解决方案?


答案 1

现在,随着SPR-6870的分辨率,这个问题在春季得到了解决。有关详细信息,请参阅那里的解决方案注释。此修复程序自版本 3.2.0.RELEASE 和 3.1.2 起可用。


答案 2

大多数Spring应用程序在启动时将事物连接在一起,而不是在运行时从上下文中获取bean。即便如此,除非您在应用程序的常规运行期间经常更改应用程序上下文,否则您不应该多次获取Bean。

鉴于此,如果您的用户抱怨速度缓慢,那么您真正的问题似乎是太多的bean查找;你使用一种较慢的手段来做到这一点,这才刚刚浮出水面真正的问题。

我会尝试迁移到Java配置(在Java中配置您的依赖项,我相信在Spring 3.0中受支持),并将您的应用程序配置为在启动时连接所有bean。这还具有一个优点,即如果无法满足依赖项,你的应用将无法启动。


推荐