诚心求助 Spring 注入式 AspectJ 切面时 ClassNotFoundException 的问题

2019-06-03 01:30:00 +08:00
 Febers

楼主最近在学 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,感谢你看到这里,希望能得到建设性意见,谢谢。

1331 次点击
所在节点    Java
12 条回复
Allianzcortex
2019-06-03 01:51:15 +08:00
1. 《 Spring In Action 》第五版已经出来,集成了 Spring Boot,并且取消了 AspectJ 这部分内容(专门再搜了下,整本书没有出现 "AspectJ" 这个关键词),楼主考虑换成这个版本的?

2. 不知道为什么会出现这种情况,已经好久没有看过 XML 配置文件了...我当时用注解实现的 AspectJ 代码在这里 https://github.com/Allianzcortex/LaraForum/blob/master/src/main/java/com/laraforum/authorization/RolesAndPermissionsChecker.java#L52,调用时就像 Python @Decorator 一样调用: https://github.com/Allianzcortex/LaraForum/blob/104b16fcd8847aa84bb9f5947d57f8c848fb3e5a/src/main/java/com/laraforum/controller/OtherController.java#L86
Febers
2019-06-03 01:57:31 +08:00
@Allianzcortex 其实我是准备重点学习 Spring Boot,但是绕不过 Spring,所以准备快速过一遍,但是没想到遇到问题了。
我看了你的代码了,其实我也不喜欢 XML 文件,所以一直用的注解配置,然后也没出问题,直到遇到了 aj 文件。出问题了才用 XML 过一遍好定位原因。
感谢你的回复。
Febers
2019-06-03 02:01:35 +08:00
整个问题可以概括为: 为什么 Spring 无法识别 aspect 类型的类文件
Allianzcortex
2019-06-03 02:09:32 +08:00
@Febers 不知道为什么会有 .aj 这种文件,一开始就是在 .java 里定义切面。官网和博客资料会好很多,那本书太大而全了,真要跑起来还要学 thymeleaf 模板🙄
Febers
2019-06-03 02:19:09 +08:00
@Allianzcortex 对的,我也很无语╯﹏╰
lil460982475
2019-06-03 08:55:57 +08:00
以前看过相关概念,但没有实践过。.aj 文件并不是 Java 类,你虽然有这个文件,xml 也定义了,但应该不能直接识别,需要将 .aj 通过专门的编译器编译成 class 文件。

看下这篇文章,看有没有帮助。https://blog.csdn.net/javazejian/article/details/56267036
lil460982475
2019-06-03 08:58:10 +08:00
对了,spring 你要使用切面技术,并不需要使用 apectj 框架的语法去定义,spring aop 已经能让你使用 java+spring 代码去实现了,没必要
Febers
2019-06-03 10:33:28 +08:00
@lil460982475 对的,目前的进展就到这一步,需要 ajc 编译器,等会查阅相关资料试试
Febers
2019-06-03 10:35:41 +08:00
@lil460982475 应该就是这篇文章所讲:https://m.w3cschool.cn/intellij_idea_doc/intellij_idea_doc-woks2nde.html

Spring aop 确实已经满足要求,不过我是一边学下边做笔记,遇到这种情况跳不过去
gz911122
2019-06-03 11:01:46 +08:00
AspectJ 和 spring 没有什么关系的

AspectJ 插件装了吗?
ajc 设置了吗?
gz911122
2019-06-03 11:04:27 +08:00
@gz911122 再概括一下,spring aop 和 aspectJ 一毛钱关系也没有
只不过 spring 借用了 aspectJ 的注解而已
Febers
2019-06-03 11:44:18 +08:00
@gz911122 #10 AspectJ 插件一开始就装了。按照[ Mojo's AspectJ Maven Plugin]( https://www.mojohaus.org/aspectj-maven-plugin/usage.html)这个插件设置了 ajc,IDE Compiler 也没问题。但是又遇到问题了,这回是 ajc 的

Error:ajc: can't find critical required type java.io.Serializable
Error:ajc: can't find critical required type java.lang.Cloneable

Google 只找到几条零碎的信息

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/570139

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX