我们目前使用Spring 4.0.9
我们的网络应用程序在启动时变得越来越慢,在过去几个月内从200秒变为600秒。
我做了一些分析,最大的问题是方法...
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit)
... org.springframework.beans.factory.support.DefaultListableBeanFactory 类
开发人员越来越多地使用@Autowired连接其依赖项。它似乎在启动时(构建bean工厂时)getBeanNamesForType遍历整个bean名称列表以查找适当的类型。如果你有很多像我们这样的bean(1400),那么这个方法调用需要花费0.5秒才能完成自动装配bean中的一个属性。所以你可以想象浪费了很多时间。
我可以看到以前的修补程序已放入DefaultListableBeanFactory,所以在运行时创建和自动装配非单例bean时,它非常快,因为bean名称是按类型
缓存的请参阅https://jira.spring.io/browse/SPR-6870
但是,只有在bean工厂全部初始化后才能使用此缓存行为,因此在应用程序启动时仍然会遇到相同的问题。
我正在查看代码,但它非常复杂。我想知道是否有一种方法可以在构造bean工厂时对bean类型进行缓存。作为一个快速测试,我从...
修改了DefaultListableBeanFactory的代码 @Override
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
return doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
}
Map<Class<?>, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
String[] resolvedBeanNames = cache.get(type);
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
resolvedBeanNames = doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}
...到...
@Override
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
Map<Class<?>, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType1 : this.singletonBeanNamesByType1);
String[] resolvedBeanNames1 = cache.get(type);
if (resolvedBeanNames1 != null) {
return resolvedBeanNames1;
}
resolvedBeanNames1 = doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
cache.put(type, resolvedBeanNames1);
}
return resolvedBeanNames1;
}
Map<Class<?>, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
String[] resolvedBeanNames = cache.get(type);
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
resolvedBeanNames = doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}
基本上我所做的就是即时缓存类型。这似乎有效,并允许我们的应用程序快速启动两次。
但是我知道我的快速测试没有考虑所有Spring方案。必须有理由每次检查整个bean定义列表吗?
有什么想法吗?