Spring Proxy类和Kotlin中的Null指针异常


问题内容

我在spring与Kotlin一起遇到一些问题。

我有一个控制器bean(没有接口btw),它具有通过主构造函数自动连接的服务bean。

除非我为控制器使用缓存批注,否则它会完美地工作。显然,spring缓存会在处理缓存的后台生成一个代理类。

我的代码如下所示:

@RestController
@RequestMapping("/regions/")
open class RegionController @Autowired constructor(val service: RegionService) {
    @RequestMapping("{id}", method = arrayOf(RequestMethod.GET))
    @Cacheable(cacheNames = arrayOf("regions"))
    fun get(@PathVariable id: Long): RegionResource {
        return this.service.get(id)
    }
}

现在的问题是当执行该方法的零指示字例外,实际上this.servicenull这在技术上是不可能的,因为它是在一个科特林非空变量。

我假设spring生成的类代理使用空值而不是自动装配的bean初始化了该类。这一定是使用kotlin和spring的常见陷阱。您是如何规避这个问题的?


问题答案:

在Kotlin ,默认情况下,类和成员都是最终的。

为了使代理库(CGLIBjavaassist)能够代理一个方法,必须将其声明 为非最终类 且在 非最终
类中因为这些库通过子类实现代理。将您的控制器方法更改为:

@RequestMapping("{id}", method = arrayOf(RequestMethod.GET))
@Cacheable(cacheNames = arrayOf("regions"))
open fun get(@PathVariable id: Long): RegionResource {
    return this.service.get(id)
}

您可能会在控制台中看到有关RegionController方法不接受代理的警告。

[Kotlin编译器插件](https://kotlinlang.org/docs/reference/compiler-

plugins.html#spring-support)

Kotlin团队已经意识到了这一困难,并创建了一个插件来标记标准AOP代理候选人,例如@Component使用open

您可以在以下位置启用插件build.gradle

plugins {
  id "org.jetbrains.kotlin.plugin.spring" version "1.1.60"
}