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

2022-09-01 23:14:01

目前,我尝试用 Kotlin 重写我的 Java Spring Boot Application。我遇到了一个问题,在我的所有使用依赖关系注入进行注释的类中都无法正常工作(所有实例都是)。下面是一个示例:@Servicenull

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

在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;
    }

如果我在 Kotlin 中注释组件,一切正常:@Component

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

Google为Kotlin提供了许多不同的方法,我尝试过,但结果都是一样的,我想知道Kotlin和Java之间的区别是什么,以及我如何解决这个问题?@AutowiredNullPointerException


答案 1

我刚刚遇到了完全相同的问题 - 注入效果很好,但是在添加@Transactional注释后,所有自动连接的字段都是空的。

我的代码:

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

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

} 

这里的问题是,默认情况下,这些方法在 Kotlin 中是最终的,因此 Spring 无法为该类创建代理:

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

“打开”该方法解决了这个问题:

固定代码:

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

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

} 

答案 2

我在使用Kotlin时遇到了同样的问题,但空实例是一个JpaRepository。当我将注释添加到服务中的方法时,我收到一条消息,说我继续将类和方法标记为.很简单,对吧?!嗯,不完全是。@TransactionalMethods annotated with '@Transactional' must be overridableopen

虽然这编译,但我在执行时将所需的存储库设置为空。我能够通过两种方式解决问题:

  1. 将类及其所有方法标记为:open
open class FooService(private val barRepository: BarRepository) {
    open fun aMethod(): Bar {
        ...
    }

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

这有效,但是将类中的所有方法都标记为 可能看起来有点奇怪,所以我尝试了其他方法。open

  1. 声明接口:
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 {
        ...
    }
}

通过这种方式,您仍然可以使用注释,因为所有方法都是可重写的,并且您不需要在任何地方都使用。open

希望这有帮助=)


推荐