【问题标题】:Spring AOP slow startup timeSpring AOP 启动慢
【发布时间】:2011-01-14 12:06:23
【问题描述】:

我们使用带有@AspectJ 样式注释和<aop:aspectj-autoproxy/> 的Spring (3.0.5) AOP。我们将它用于事务、审计、分析等。它工作正常,只是应用程序的启动时间随着更多代码的添加而不断增长。

我做了一些分析,发现大部分时间都花在了 Spring 容器初始化期间,更具体地说是org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(String, ObjectFactory) - 大约需要 35 秒。 org.springframework.aop.support.AopUtils.canApply(Pointcut, Class, boolean) - 大约需要 15 秒。

我的目标是让应用程序在 5-10 秒内启动,而不是像现在这样约 45 秒,所以任何提示都将不胜感激。

【问题讨论】:

  • 匆忙下结论 Spring AOP 导致启动性能问题。(考虑到编织发生在运行时)。您是否使用 Jconsole 或 visualVm 检查了 JVM 的统计信息。您是否有一些 bean 的自定义 init 方法。您是否尝试过使用延迟初始化。 (通过 bean 中的惰性初始化属性)?
  • 这些是我将遵循的步骤。 1- 正常加载时检查 JVM 统计信息。 2. 将 beans 的 lazy-init 属性设为默认值,然后再次检查 jvm stat(内存使用情况等)。 3-如果仍然没有显着改善,我将关闭自动代理方面。就像我提到的,如果我必须下注,我会准备打赌它不会影响加载时间。
  • 我很确定这是编织,因为我花了很多时间对 Yourkit 进行分析,在启动期间只进行线程转储并放置一些断点和所有指向 AOP 编织的点。但是当您说关闭方面自动代理时,我很好奇您建议的替代方案是什么?谢谢,尤瓦尔
  • 你有解决这个问题的办法吗?我也面临同样的问题。
  • 不,没有解决方案,我们只能忍受它......

标签: java performance spring aop spring-aop


【解决方案1】:

我遇到了同样的问题,原来 Spring AOP 自动代理在启动时会花费大量时间使用 bcel 加载类(没有缓存,因此一次又一次加载相同的类,如 java.lang.Object...)试图找出适用的建议。 通过编写更细粒度的切入点(例如在内部使用,@within)可以对其进行一定程度的改进,但如果您的所有切入点都使用@annotation 编写,我找到了一个效果更好的解决方案。

1) 使用以下命令停用自动代理:spring.aop.auto=false

2) 编写一个 AnnotationAwareAspectJAutoProxyCreator 的自定义子类来根据您自己的标准过滤要装饰的 bean,例如这个是基于包和注释的:

@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName,   TargetSource targetSource) {
  if (beanClass != null && isInPackages(beansPackages, beanClass.getName()) &&   hasAspectAnnotation(beanClass)) {
    return super.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
  } else {
    return DO_NOT_PROXY;
  }
}

在我的例子中,启动时间从 60 秒缩短到 15 秒。

希望对人和北极熊有帮助

【讨论】:

    【解决方案2】:

    从您发布的内容来看,您似乎使用了加载时间编织,这会导致启动惩罚,因为系统必须在加载所有类时编织它们。如果您主要关心的是启动时间,那么我建议您切换到编译时间编织。您可以在 spring 文档(第 6 章第 8 节)或 AspectJ 站点 (http://www.eclipse.org/aspectj/docs.php) 中找到有关如何执行此操作的说明

    使用 AspectJ 编译器切换到编译时编织是相对直接的:

    1. 删除 &lt;aop:aspectj-autoproxy/&gt; 符号 从您的上下文文件中。
    2. 添加一个 aspectJ 编译步骤到您的构建 文件。在 AspectJ 网站上,您应该 能够找到一个蚂蚁插件, codehaus 有一个 Maven 插件。这里 是我们如何做的例子。

    对于 Maven:

    <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>aspectj-maven-plugin</artifactId>
         <version>1.3</version>
         <configuration>
         <verbose>true</verbose>
          <source>1.6</source>
          <target>1.6</target>
          <complianceLevel>1.6</complianceLevel>
          <showWeaveInfo>true</showWeaveInfo>
          <aspectLibraries>
            <aspectLibrary>
                                    <groupId>org.springframework</groupId>
                                    <artifactId>spring-aspects</artifactId>
                                </aspectLibrary>
                            </aspectLibraries>
                        </configuration>
                        <executions>
                            <execution>
                                <goals>
                                    <goal>compile</goal>   
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
    

    对于蚂蚁

     <taskdef
                resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties">
                <classpath>
                    <pathelement location="${lib.dir}/AspectJ_1.6.8/aspectjtools.jar"/>
                </classpath>
            </taskdef>
    
      <iajc aspectPath="${file.reference.spring-aspects.jar}; ${build.classes.dir}/path/to/custom/aspects"
                  classpath="${lib.dir}/AspectJ_1.6.8/aspectjrt.jar; ${javac.classpath}"
                  inpath="${build.classes.dir}"
                  destDir="${build.classes.dir}"
                  showWeaveInfo="true" />
    

    【讨论】:

    • 感谢您的提示,但切换到编译时编织不是一种选择,与我一起工作的人强烈反对编译后步骤。
    • @Yuval:您至少可以尝试一下,以确认加载时编织导致延迟吗?
    • @Bruno:我第一次尝试,它运行得并不顺利,但是当我有更多时间和报告时,我会再做一些工作,谢谢。
    • @Yuval 你遇到了什么问题?
    • 我在这里描述了我遇到的问题:stackoverflow.com/questions/4841843/…
    【解决方案3】:

    如果您有很多非单例 bean,显然这是一个已知问题。 Spring 3.1 似乎有一个修复:https://jira.springsource.org/browse/SPR-7328

    【讨论】:

    • 感谢您的链接,这可能不是这种情况,我们的大多数 bean 都是单例的,但这很可能是连接的。
    • 不幸的是,使用缓存的 AopUitls 也没有帮助
    【解决方案4】:

    我不确定它是否适用于您的情况,但Spring performance can be improved by empolying a CachingBeanFactory

    这通常适用于连接 bean 时,但根据应用和连接方面的方式,它可能会带来改进。

    【讨论】:

      【解决方案5】:

      你有任何循环依赖吗?这就是杀死我当前应用的原因。

      我知道这不是一个真正的解决方案,但我会分解上下文以在不同的虚拟机中运行不同的服务,SOA 风格。这应该让您的所有应用程序的启动时间都很短,并且还应该为您提供一些灵活性,以便更轻松地更改这些服务的实现、测试少量代码等。

      我没有在我的一个应用程序中这样做,现在启动时间大约是 3/4 分钟,这太疯狂了(我们有几千个 bean)。这个问题并没有消失,只会变得更糟,但如果你尝试解决它的时间太晚,应用程序就会太大,而且很难拆分。

      我会研究的另一件事是休眠,创建会话工厂可能会很慢。

      【讨论】:

      • 感谢您的提示,您怎么知道循环依赖会导致应用程序崩溃?
      • 您使用什么 IDE?例如 Intellij IDEA 在其“分析”菜单选项下进行循环依赖分析。
      【解决方案6】:

      在我将 jdk1.7 改回 jdk1.6 之前,我遇到了同样的问题。 通过 jdk1.7,我的应用程序在“初始化 Spring 根 WebApplicationContext”上挂起超过 30 秒。换回后,10秒后启动。

      【讨论】:

        猜你喜欢
        • 2015-10-25
        • 2012-03-28
        • 2011-07-08
        • 2012-03-11
        • 2018-09-11
        • 2020-09-15
        • 2021-12-07
        • 1970-01-01
        • 2011-01-06
        相关资源
        最近更新 更多