V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Febers
V2EX  ›  Java

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

  •  
  •   Febers · 2019-06-03 01:30:00 +08:00 · 1307 次点击
    这是一个创建于 1999 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    第 1 条附言  ·  2019-06-03 12:30:08 +08:00

    并不愿意在这上面花费过多时间和精力,目的还是在于理解 Spring AOP 的知识并完成博客的学习笔记:Spring 学习笔记(三):面向切面 | ReBE

    楼主将不再纠结 AspectJ 的问题,留着日后有空解决吧

    12 条回复    2019-06-03 11:44:18 +08:00
    Allianzcortex
        1
    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
        2
    Febers  
    OP
       2019-06-03 01:57:31 +08:00 via Android
    @Allianzcortex 其实我是准备重点学习 Spring Boot,但是绕不过 Spring,所以准备快速过一遍,但是没想到遇到问题了。
    我看了你的代码了,其实我也不喜欢 XML 文件,所以一直用的注解配置,然后也没出问题,直到遇到了 aj 文件。出问题了才用 XML 过一遍好定位原因。
    感谢你的回复。
    Febers
        3
    Febers  
    OP
       2019-06-03 02:01:35 +08:00 via Android
    整个问题可以概括为: 为什么 Spring 无法识别 aspect 类型的类文件
    Allianzcortex
        4
    Allianzcortex  
       2019-06-03 02:09:32 +08:00
    @Febers 不知道为什么会有 .aj 这种文件,一开始就是在 .java 里定义切面。官网和博客资料会好很多,那本书太大而全了,真要跑起来还要学 thymeleaf 模板🙄
    Febers
        5
    Febers  
    OP
       2019-06-03 02:19:09 +08:00 via Android
    @Allianzcortex 对的,我也很无语╯﹏╰
    lil460982475
        6
    lil460982475  
       2019-06-03 08:55:57 +08:00
    以前看过相关概念,但没有实践过。.aj 文件并不是 Java 类,你虽然有这个文件,xml 也定义了,但应该不能直接识别,需要将 .aj 通过专门的编译器编译成 class 文件。

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

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

    AspectJ 插件装了吗?
    ajc 设置了吗?
    gz911122
        11
    gz911122  
       2019-06-03 11:04:27 +08:00
    @gz911122 再概括一下,spring aop 和 aspectJ 一毛钱关系也没有
    只不过 spring 借用了 aspectJ 的注解而已
    Febers
        12
    Febers  
    OP
       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 只找到几条零碎的信息
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5312 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 95ms · UTC 08:04 · PVG 16:04 · LAX 00:04 · JFK 03:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.