楼主最近在学 Spring,按照《 Spring in Action 》上面的运行时注入 AspectJ 切面的 demo 敲,发现了一个目前找不到解决办法的问题,代码运行时提示 找不到引用( Java/Kotlin )、ClassNotFoundException ( XML 文件),Google 了半天,在 StackOverflow 上看到了相似的情况,同样没有找到解决办法,自己也琢磨不出,只能向有经验的 V 友求助
demo 大致思路:一个表演类“ MyPerformance ”,其中定义方法 perform,也就是切点。一个 AspectJ 类 CriticAspect,定义在同名 aj 文件中,在其中定义通知。表演结束之后打印一段字符串。具体代码如下
@Component open class MyPerformance: Performance { override fun perform() { println("Start perform") } } AspectJ 文件 CriticAspect.aj
public aspect CriticAspect { public CriticAspect() { } pointcut performance(): execution(* concert.MyPerformance.perform(..)); after(): performance() { System.out.println("something"); } } 下面是 XML 配置文件 concert.xml 。根据书上所说,Spring 不能负责创建 CriticAspect,需要由 AspectJ 运行期创建,因此得为 Spring 获得已经由 AspectJ 创建好的实例的引用。书上的例子采用的是 XML 的方式,通过切面的静态方法 aspectOf 返回实例
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cOntext="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="concert" /> <aop:aspectj-autoproxy /> <bean class="concert.CriticAspect" factory-method="aspectOf" /> </beans> 下面是测试代码
@RunWith(SpringJUnit4ClassRunner::class) @ContextConfiguration(locatiOns= ["classpath:concert.xml"]) class PerformTest { @Autowired lateinit var performance: Performance @Test fun perform() { performance.perform() } } 运行失败,报错信息摘录如下
...... 严重: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@491cc5c9] to prepare test instance [concert.PerformTest@74c79fa2] java.lang.IllegalStateException: Failed to load ApplicationContext ...... Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [concert.CriticAspect] for bean with name 'concert.CriticAspect#0' defined in class path resource [concert.xml]; nested exception is java.lang.ClassNotFoundException: concert.CriticAspect ...... Caused by: java.lang.ClassNotFoundException: concert.CriticAspect ...... 如果以 JavaConfig 的方式配置,按照 StackOverflow 上一个回答 我找到了 aspectOf 的接口,以下为 Kotlin 代码
@Configuration @EnableAspectJAutoProxy @ComponentScan open class ConcertConfig { @Bean open fun criticAspect(): CriticAspect = org.aspectj.lang.Aspects.aspectOf(CriticAspect::class.java) } 运行之后 IEDA 报错
Error:(13, 30) Kotlin: Unresolved reference: CriticAspect Java 形式我也试过,一样的报错信息:"找不到引用: CriticAspect"。在 StackOverflow 上看到了相同的问题How to resolve the following AspectJ aspect ClassNotFoundException? ,两个回答都没有解决办法
除了使用 aj 文件动态织入之外的代码都是正确运行的,包括使用 Spring 支持的 AOP 注解,错误只有在引入了 AspectJ 文件之后才出现。比如将 XML 配置文件中声明 bean 的那行删去,demo 正常工作,将 JavaConfig 中那个 bean 方法去掉其他部分也能正常工作。
开发环境为 Win10 + IDEA + JDK 11 + Kotlin,感谢你看到这里,希望能得到建设性意见,谢谢。
