【发布时间】:2010-09-01 15:08:35
【问题描述】:
我在“aspectj”模式下使用 Spring 的声明性事务(@Transactional 注释)。在大多数情况下,它的工作原理与应有的完全一样,但对于其中一种情况却没有。我们可以称它为Lang(因为它实际上是这样称呼的)。
我已经能够将问题定位到加载时间编织器。通过在 aop.xml 中打开调试和详细日志记录,它列出了所有正在编织的类。问题类Lang确实在日志中根本没有提到。
然后我在Lang的顶部放了一个断点,导致Eclipse在Lang类被加载时挂起线程。这个断点在 LTW 编织其他类时被命中!所以我猜它要么尝试编织 Lang 并且失败并且不输出它,或者其他一些类有一个引用,它强制它在实际有机会编织它之前加载 Lang。
但我不确定如何继续调试它,因为我无法以较小的规模重现它。关于如何继续的任何建议?
更新:也欢迎其他线索。例如,LTW 实际上是如何工作的?似乎发生了很多魔术。是否有任何选项可以从 LTW 获得更多调试输出?我目前有:
<weaver options="-XnoInline -Xreweavable -verbose -debug -showWeaveInfo">
我忘了汤姆之前提到过:spring-agent 被用来允许 LTW,即InstrumentationLoadTimeWeaver。
根据 Andy Clement 的建议,我决定检查 AspectJ 转换器是否通过了课程。我在ClassPreProcessorAgent.transform(..) 中设置了一个断点,尽管Lang 类与其他类(Jetty 的WebAppClassLoader 的一个实例)是由同一个类加载器加载的,但它似乎从未到达该方法。
然后我继续在InstrumentationLoadTimeWeaver$FilteringClassFileTransformer.transform(..) 中放置一个断点。 Lang 甚至连那个都没有。而且我相信应该为 所有 加载的类调用该方法,无论他们使用什么类加载器。这开始看起来像:
- 我的调试有问题。可能
Lang在 Eclipse 报告它的时候没有加载 - Java 错误?牵强附会,但我想它确实会发生。
下一条线索:我打开了-verbose:class,它看起来好像Lang 正在被过早加载 - 可能是在将变压器添加到 Instrumentation 之前。奇怪的是,我的 Eclipse 断点没有捕捉到这个加载。
这意味着 Spring 是新的嫌疑人。 ConfigurationClassPostProcessor 中似乎有一些处理加载类以检查它们。这可能与我的问题有关。
ConfigurationClassBeanDefinitionReader 中的这些行导致Lang 类被读取:
else if (metadata.isAnnotated(Component.class.getName()) ||
metadata.hasAnnotatedMethods(Bean.class.getName())) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
return true;
}
特别是metadata.hasAnnotatedMethods()在类上调用getDeclaredMethods(),它会加载该类中所有方法的所有参数类。我猜这可能不是问题的结束,因为我认为这些类应该被卸载。 JVM 是否会因为不可知的原因缓存类实例?
【问题讨论】:
标签: java aop aspectj spring-aop