kotlin AspectJ不能在没有接口和在配置类中定义的bean上工作

swvgeqrz  于 2023-01-31  发布在  Kotlin
关注(0)|答案(1)|浏览(210)

我创建了一个演示应用程序来重现它:

    • 演示服务**
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未实现任何接口。

  1. Bean已在Configuration类中注册。
f0brbegy

f0brbegy1#

与原生AspectJ不同,Spring AOP是基于动态代理的。为了代理一个类,它不能是final。用Kotlin的术语来说,它必须是open。此外,为了代理一个方法,它也不能是final,也就是说,你还需要对方法进行open。请参见Baeldung教程。
因此,请使用open fun test(),然后它将按预期工作。

    • 后续问题更新:**

为什么即使函数是final,使用@Service也能正常工作?
因为在您的构建中,您可能会使用启用Spring支持的Kotlin全开放编译器插件。如果我是您,我无论如何都不会使用@Bean工厂方法,而只是直接在实现类上使用@Component@Service或类似的Spring注解。
当然,除了Spring版本之外,您还可以使用通用的全开放插件,然后执行以下操作:

annotation class OpenMe()
@OpenMe
class DemoService {
  fun test() {
    println("test function is executed.")
  }
}

然后,在Maven中,您可以执行以下操作:

<plugin>
  <groupId>org.jetbrains.kotlin</groupId>
  <artifactId>kotlin-maven-plugin</artifactId>
  <configuration>
    <args>
      <arg>-Xjsr305=strict</arg>
    </args>
    <compilerPlugins>
      <plugin>all-open</plugin>
      <plugin>spring</plugin>
    </compilerPlugins>
    <pluginOptions>
      <option>all-open:annotation=org.acme.OpenMe</option>
    </pluginOptions>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-maven-allopen</artifactId>
      <version>${kotlin.version}</version>
    </dependency>
  </dependencies>
</plugin>

这样你就不需要在服务类或方法上使用任何open关键字了,并且可以继续使用你的@Bean工厂方法,但是我认为这比使用Spring注解要复杂得多--约定高于配置。

相关问题