我是一名学生,正在做一个Java + Spring Boot项目,我把Controller部分改成了Kotlin!然而,当我测试它时,所有使用@Before Aop的API在从控制器调用服务时都会生成NPE,并且服务为空! Java Controller -> AOP 工作正常,但不知道为什么。
下面是代码
控制器
@RestController
@RequestMapping("/")
open class SampleController (
private val sampleService: SampleService){
@GetMapping
fun test(){
println("TEST In ")
}
}
AOP
@Aspect
@Component
@RequiredArgsConstructor
@Slf4j
public class PreProcess{
@Before("@within(org.springframework.web.bind.annotation.RestController)")
public void doProcess(JoinPoint joinPoint) {
log.info("####### ASPECT IN ")
}
}
总结一下 如果你烧写Java Controller API,方面和控制器日志都会被记录并正常运行。
如果烧录 Kotlin 控制器 API,会出现 NPE(无法调用 SampleService,因为 this.SampleService 为 null ~~~~)
解决办法是什么?,,,,,,,
我通过创建一个新项目进行了测试,还删除了似乎相关的gradle。
您的问题似乎是由组件的初始化顺序问题引起的。当
@Before
方面尝试访问 sampleService
时,其初始化可能尚未完成,从而导致 NullPointerException
(NPE),因为它使用 sampleService
。
为了确保
sampleService
在被访问之前初始化,您可以将 sampleService
转换为 lateinit var
并使用字段注入自动装配它。您的 Kotlin 控制器可能如下所示:
@RestController
@RequestMapping("/")
open class SampleController : SampleService{
@Autowired
lateinit var sampleService: SampleService
@GetMapping
fun test() {
println("TEST In ")
}
}
请记住,由于初始化语义可能不明确,使用
lateinit var
并不总是最佳选择。
另一个潜在问题可能与 Lombok 的
@RequiredArgsConstructor
注释在 Kotlin 中使用时不兼容有关,因为 Kotlin 不会生成此注释所需的零参数构造函数。
更好的选择是您构建自己的构造函数以在方面中进行依赖项注入。
@Aspect
@Component
@Slf4j
class PreProcess(
private val sampleService: SampleService) {
@Before("@within(org.springframework.web.bind.annotation.RestController)")
fun doProcess(joinPoint: JoinPoint) {
log.info("####### ASPECT IN ")
}
}
不过,一般来说,将服务组件与方面混合起来并不是一个好主意,因为它们是针对不同的关注点的。