Spring 代理类和 Kotlin 中的空指针异常

Posted

技术标签:

【中文标题】Spring 代理类和 Kotlin 中的空指针异常【英文标题】:Null Pointer Exception In Spring Proxy Class and Kotlin 【发布时间】:2016-09-22 17:51:15 【问题描述】:

我在将 kotlin 与 spring 结合使用时遇到了一些问题。

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

除非我为控制器使用缓存注释,否则它工作得很好。显然 springs 缓存会在后台生成一个代理类来处理缓存。

我的代码如下所示:

@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,这在技术上是不可能的,因为它是 kotlin 中的非空变量。

我假设class proxies generated by spring 使用空值而不是自动装配的 bean 来初始化类。这一定是使用 kotlin 和 spring 的常见陷阱。你是如何规避这个问题的?

【问题讨论】:

【参考方案1】:

在 Kotlin 中默认为 classes and members are final。

为了让代理库(CGLIB、javaassist)能够代理方法,它必须声明为 non final 并在 non final 类中(since those libraries implement proxying by subclassing)。将您的控制器方法更改为:

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

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

The Kotlin compiler plugin

Kotlin 团队已经认识到这一困难,并创建了一个插件来标记标准 AOP 代理候选者,例如@Componentopen

您可以通过build.gradle 启用插件:

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

【讨论】:

这里值得一提:如果你有一个抽象类被一个带有@Component注解的类扩展,spring的kotlin插件默认不会打开抽象函数。子进程可以毫无问题地调用父进程,但如果外部调用父方法,它将查看所​​有空成员变量。在方法中添加open修复,或者在抽象类中添加spring注解,或者新建注解添加到kotlin-allopen插件中【参考方案2】:

很快这可能不再是问题了。

正在进行的工作是任何库(例如包括 spring)都可以在 META-INF 中指定一个文件的注释列表。一旦一个类被其中之一注释,它将默认为该类本身及其所有功能打开。对于从带注释的类继承的类也是如此。

更多详情请关注https://github.com/Kotlin/KEEP/pull/40#issuecomment-250773204

【讨论】:

与此同时,kotlin 1.6 与新的全开放编译器插件一起发布:blog.jetbrains.com/kotlin/2016/12/kotlin-1-0-6-is-here

以上是关于Spring 代理类和 Kotlin 中的空指针异常的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin小笔记kotlin中的空指针检查

Kotlinkotlin中的空指针检查

Kotlin空安全 ① ( Kotlin 的空安全机制 | 变量可空性 | 默认变量不可赋空值 | 声明可空类型变量 )

服务类Spring引导中的空指针异常[重复]

如何解决spring boot test中的空指针异常?

Spring MVC 项目中的空指针异常