我创建了一个演示应用程序来重现它:
- 演示服务**
open class DemoService {
fun test() {
println("test function is executed.")
}
}
- 人口统计方面**
@Aspect
class DemoAspect {
@Around("execution(* com.example.demo.service.DemoService.test(..))")
fun testAspect(joinPoint: ProceedingJoinPoint) {
println("before test function.")
joinPoint.proceed()
println("after test function.")
}
}
- 应用程序配置**
@Configuration
@EnableAspectJAutoProxy
class AppConfig {
@Bean
fun demoService() = DemoService()
@Bean
fun demoAspect() = DemoAspect()
}
- Spring演示应用程序**
@SpringBootApplication
@Import(AppConfig::class)
class SpringDemoApplication
fun main(args: Array<String>) {
val context = runApplication<SpringDemoApplication>(*args)
val demoService = context.beanFactory.getBean(DemoService::class.java)
demoService.test()
}
执行结果:
test function is executed.
该方面不工作,这是意料之外的。
我尝试了以下变化,他们的工作正确:
删除配置服务中的bean,并通过注解注册bean
- 演示服务**
@Service
open class DemoService {
...
}
- 应用程序配置**
@Configuration
@EnableAspectJAutoProxy
class AppConfig {
@Bean
fun demoAspect() = DemoAspect()
}
让DemoService
实现一个接口
- 演示服务**
interface DemoService {
fun test()
}
open class DemoServiceImpl: DemoService {
override fun test() {
println("test function is executed.")
}
}
- 应用程序配置**
@Configuration
@EnableAspectJAutoProxy
class AppConfig {
@Bean
fun demoService() = DemoServiceImpl()
@Bean
fun demoAspect() = DemoAspect()
}
我想了解AspectJ为什么不能处理这个组合:
1.目标Bean未实现任何接口。
- Bean已在Configuration类中注册。
1条答案
按热度按时间f0brbegy1#
与原生AspectJ不同,Spring AOP是基于动态代理的。为了代理一个类,它不能是
final
。用Kotlin的术语来说,它必须是open
。此外,为了代理一个方法,它也不能是final
,也就是说,你还需要对方法进行open
。请参见Baeldung教程。因此,请使用
open fun test()
,然后它将按预期工作。为什么即使函数是final,使用@Service也能正常工作?
因为在您的构建中,您可能会使用启用Spring支持的Kotlin全开放编译器插件。如果我是您,我无论如何都不会使用
@Bean
工厂方法,而只是直接在实现类上使用@Component
、@Service
或类似的Spring注解。当然,除了Spring版本之外,您还可以使用通用的全开放插件,然后执行以下操作:
然后,在Maven中,您可以执行以下操作:
这样你就不需要在服务类或方法上使用任何
open
关键字了,并且可以继续使用你的@Bean
工厂方法,但是我认为这比使用Spring注解要复杂得多--约定高于配置。