在常规的spring ltw中,我们对tomcat使用ltw,一般是以下两种方式。
//1 在启动项中添加javaagent选项
-javaagent:e:/spring-instrument-4.1.1.RELEASE.jar
//2 使用自定义的启动器,在META-INF/context.xml中增加以下内容
<?xml version="1.0" encoding="UTF-8" ?>
<Context>
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader" />
</Context>
这两种方式在tomcat6以及tomcat7均可以正常工作。但对于tomcat8,第1种方式已经不能再工作,仅能使用第二种方式。原因就在于tomcat8的webClassLoader已经提供了InstrumentableClassLoader接口。此接口将导致spring直接将aspectj的AspectJClassBypassingClassFileTransformer 直接添加到tomcat的classLoader中。但由于不是很正确的实现方式,导致aspect在使用tomcat8提供的classLoader时,并不能有效地对自己的advice进行weaver,导致报以下的错误信息:
java.lang.NoSuchMethodError: XXXAdvice.aspectOf()LXXXAdvice;
atXXX.index(AbcController.java:30)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
这个错误的产生在于aspectJ的初始化过程和classLoader之间的交互行为,以及tomcat8中不准确的缓存行为。