我排除了项目的一部分,以简化重现问题: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}}配置。它工作正常,但在某些情况下,它需要从应用程序上下文获取依赖项。解决该问题的最佳做法是什么?
感谢帮助。
答案 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。