Spring启动缓慢 - 在DefaultListableBeanFactory启动时未缓存的类型

时间:2016-12-16 17:53:11

标签: spring

我们目前使用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定义列表吗?

有什么想法吗?

0 个答案:

没有答案