简体   繁体   English

在@Service 中使用 Kotlin 的 Spring Boot @Autowired 始终为 null

[英]Spring Boot @Autowired with Kotlin in @Service is always null

Currently I try to rewrite my Java Spring Boot Application with Kotlin.目前我尝试用 Kotlin 重写我的 Java Spring Boot 应用程序。 I encountered a problem that in all of my classes which are annotated with @Service the dependency injection is not working correctly (all instances are null ).我遇到了一个问题,在我所有用@Service注释的类中,依赖注入都不能正常工作(所有实例都是null )。 Here is an example:下面是一个例子:

@Service
@Transactional
open class UserServiceController @Autowired constructor(val dsl: DSLContext, val teamService: TeamService) {
  //dsl and teamService are null in all methods
}

Doing the same in Java works without any problems:在 Java 中做同样的事情没有任何问题:

@Service
@Transactional
public class UserServiceController
{
    private DSLContext dsl;
    private TeamService teamService;

    @Autowired
    public UserServiceController(DSLContext dsl,
                             TeamService teamService)
    {
        this.dsl = dsl;
        this.teamService = teamService;
    }

If I annotate the component with @Component in Kotlin everything works fine:如果我在 Kotlin 中使用@Component注释组件,一切正常:

@Component
open class UserServiceController @Autowired constructor(val dsl: DSLContext, val teamService: TeamService) {
  //dsl and teamService are injected properly
}

Google provided many different approaches for Kotlin and @Autowired which I tried but all resulted in the same NullPointerException I would like to know what the difference between Kotlin and Java is and how I can fix this? Google 为 Kotlin 和@Autowired提供了许多不同的方法,我尝试过,但都导致了相同的NullPointerException我想知道 Kotlin 和 Java 之间的区别是什么以及如何解决这个问题?

I just bumped into exactly same issue - injection worked well, but after adding @Transactional annotation all the autowired fields are null.我刚刚遇到了完全相同的问题 - 注入效果很好,但是在添加 @Transactional 注释后,所有自动装配的字段都为空。

My code:我的代码:

@Service
@Transactional  
open class MyDAO(val jdbcTemplate: JdbcTemplate) {

   fun update(sql: String): Int {
       return jdbcTemplate.update(sql)
   }

} 

The problem here is that the methods are final by default in Kotlin, so Spring is unable to create proxy for the class:这里的问题是 Kotlin 中的方法默认是 final 的,因此 Spring 无法为该类创建代理:

 o.s.aop.framework.CglibAopProxy: Unable to proxy method [public final int org.mycompany.MyDAO.update(...

"Opening" the method fixes the issue: “打开”方法解决了这个问题:

Fixed code:固定代码:

@Service
@Transactional  
open class MyDAO(val jdbcTemplate: JdbcTemplate) {

   open fun update(sql: String): Int {
       return jdbcTemplate.update(sql)
   }

} 

Which Spring Boot version do you use?您使用哪个 Spring Boot 版本? Since 1.4 Spring Boot is based on Spring Framework 4.3 and since then you should be able to use constructor injection without any @Autowired annotation at all.由于 1.4 Spring Boot 基于 Spring Framework 4.3,从那时起您应该能够使用构造函数注入而无需任何@Autowired注释。 Have you tried that?你试过吗?

It would look like this and works for me:它看起来像这样并且对我有用:

@Service
class UserServiceController(val dsl: DSLContext, val teamService: TeamService) {

  // your class members

}

I faced the same problem working with Kotlin but the null instance was a JpaRepository.我在使用 Kotlin 时遇到了同样的问题,但 null 实例是 JpaRepository。 When I added the @Transactional annotation to a method inside a service, I got a message saying Methods annotated with '@Transactional' must be overridable so I went ahead and marked both, the class and the method as open .当我将@Transactional注释添加到服务内的方法时,我收到一条消息,说Methods annotated with '@Transactional' must be overridable所以我继续将类和方法都标记为open Easy, right?!容易吧?! Well, not quite.嗯,不完全是。

Although this compiles, I got the required repository as null at execution time.尽管可以编译,但我在执行时将所需的存储库设为 null。 I was able to solve the problem in two ways:我能够通过两种方式解决这个问题:

  1. Mark the class and ALL of its methods as open :将类及其所有方法标记为open
open class FooService(private val barRepository: BarRepository) {
    open fun aMethod(): Bar {
        ...
    }

    @Transactional
    open fun aTransactionalMethod(): Bar {
        ...
    }
}

This works but having all the methods in a class marked with open might look a bit odd, so I tried something else.这可行,但将类中的所有方法都标记为open可能看起来有点奇怪,所以我尝试了其他方法。

  1. Declare an interface:声明一个接口:
interface IFooService {
    fun aMethod(): Bar

    fun aTransactionalMethod(): Bar
}

open class FooService(private val barRepository: BarRepository) : IFooService {
    override fun aMethod(): Bar {
        ...
    }

    @Transactional
    override fun aTransactionalMethod(): Bar {
        ...
    }
}

This way you can still use the annotation since all the methods will be overridable and you won't need to use open everywhere.这样你仍然可以使用注解,因为所有的方法都是可覆盖的,你不需要在任何地方都使用open

Hope this helps =)希望这会有所帮助 =)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM