如何在AspectJ编译器中使用Spring @Component批注

时间:2018-12-01 06:24:17

标签: java spring aop aspectj

我排除了项目的一部分,以简化重现问题:GitHub repo。 当我用Javac编译它时,一切都会按预期进行。打开URL /user//user/2/时,我看到在控制台中登录:

Access: execution(List ru.krivochenko.demo.user.UserController.getAll()) Access: execution(User ru.krivochenko.demo.user.UserController.getOne(Integer))

但是我想使用AspectJ编译器。当我切换到它时,会发生错误:

java.lang.NoSuchMethodError: ru.krivochenko.demo.logging.LoggingAspect: method <init>()V not found

据我了解,发生这种情况是因为LoggingAspect中没有no-args构造函数。如果添加它,则会出现另一个错误,因为未注入logger

java.lang.NullPointerException: null at ru.krivochenko.demo.logging.LoggingAspect.beforeGettingUsers(LoggingAspect.java:28) ~[classes/:na]

所以,我们怎么看,AspectJ忽略了带有args的Autowired构造函数。

在我的仓库的分支via-setter中,我实现了另一个解决方案。我删除了@Component的{​​{1}}批注,并将构造函数注入替换为setter注入。在LoggingAspect中,我添加了DemoApplication.java的{​​{1}}配置。它工作正常,但在某些情况下,它需要从应用程序上下文获取依赖项。解决该问题的最佳做法是什么?

感谢帮助。

2 个答案:

答案 0 :(得分:0)

您通过setter注入配置方面的方法对我来说是有效的。有关如何将AspectJ与Spring结合使用的更多信息,请查看相应的chapter in the Spring manual,特别是有关如何configure AspectJ aspects by Spring IoC的描述。它主要是在LTW的背景下进行解释的,但它对于CTW的工作原理几乎相同。

答案 1 :(得分:0)

Spring Aspects和编译时编织不会自动集成。这是主要的原因,因为Aspectj和spring是相当分开的,我怀疑Spring的推荐方法是不使用编译时编织。

因此,默认情况下,Aspects不是弹簧魔术,我们需要添加一些管道以确保它们是正确的。

在这方面,重要的是要注意,方面不是由Spring管理的(它们是由Aspectj管理的,因此我们需要添加一些内容以确保它们受到管理)。

这就是为什么您需要方面的无参数构造函数的原因(因此必须使用字段注入)。

传统上,我不得不将以下xml添加到我的xml配置文件中:

<bean id="securityAspect" class="com.<skip>.security.AuthorizationAspect"
        factory-method="aspectOf" autowire="byType" />

之所以可以这样做是因为AspectJ编译器将静态方法AspectOf添加到方面,并且该方法可用于获取Aspectj创建(和使用)的Aspect实例。

此方法显然在源代码中不可用,因此我们不能仅添加到应用程序类(DemoApplication):

@Bean
public LoggingAspect loggingAspect() {
    return LoggingAspect.aspectOf();
}

那该怎么办?我的下一个选择是编写一些反射性代码来调用此方法,然后查看了very helpful example,它确切地说明了您的需求-AspectJ的Aspects类具有实用程序方法,可以为我们完成此工作,因此添加以下内容在我们的DemoApplication中,我们取得了成功:

@Bean
public LoggingAspect loggingAspect() {
    return Aspects.aspectOf(LoggingAspect.class);
}

顺便说一句,从LoggingAspect中删除@Component,因为这将意味着Aspectj和Spring都将创建该类的实例...

顺便说一句,我还建议您将以下内容添加到测试类中,以在测试中演示问题:

@Autowired
private UserController controller;

@Test
public void contextLoads() {
    controller.getAll();
    controller.getOne(1);
}

顺便说一句,使用@Configurable解决此问题的其他建议。我怀疑这可能有效,但您需要确保在AspectJ编译时配置中包含spring方面java,并且我不确定它可能仍无法正常工作,因为我不确定Spring上下文是否会及时准备就绪。也就是说,如果Aspect是在Spring上下文之前创建的,则@Configurable将不起作用,因为尚未创建要注入的bean。