【问题标题】:Spring Boot @Autowired with Kotlin in @Service is always null@Service 中带有 Kotlin 的 Spring Boot @Autowired 始终为空
【发布时间】:2017-05-08 23:21:22
【问题描述】:

目前我尝试用 Kotlin 重写我的 Java Spring Boot 应用程序。我遇到了一个问题,在我所有使用@Service 注释的类中,依赖注入都无法正常工作(所有实例都是null)。这是一个例子:

@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 和 @Autowired 提供了许多不同的方法,我尝试了这些方法,但结果都是相同的 NullPointerException 我想知道 Kotlin 和 Java 之间的区别是什么以及如何解决这个问题?

【问题讨论】:

  • 你试过把 val 改成 var 吗?
  • 是的,我都试过了。
  • 尝试在 val 之前添加 @Autowired 并删除构造函数。这对我有用
  • 也许你使用的是GenericApplicationContext而不是AnnotationConfigApplicationContext

标签: java spring spring-mvc spring-boot kotlin


【解决方案1】:

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

我的代码:

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

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

} 

这里的问题是 Kotlin 中的方法默认是 final 的,所以 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。当我将@Transactional 注释添加到服务内的方法时,我收到一条消息说Methods annotated with '@Transactional' must be overridable,所以我继续将类和方法都标记为open。容易,对吧?!嗯,不完全是。

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

  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

希望这会有所帮助 =)

【讨论】:

  • 我不明白.. 尝试了完全相同的方法 - 但只要我添加 OPEN 类 - 它就会升级到 dep。注射。 val 存储库:Foo 为 NULL。当我删除 Open 时,它不允许我应用事务。太生气了
【解决方案3】:

您使用哪个 Spring Boot 版本?由于 1.4 Spring Boot 基于 Spring Framework 4.3,从那时起您应该能够使用构造函数注入,而无需任何 @Autowired 注释。你试过吗?

它看起来像这样并且对我有用:

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

  // your class members

}

【讨论】:

  • 嗨,有没有办法做到这一点,而无需获得 No default constructor found 并且不使属性为空? (仅供参考,我的一些参数是存储库)
  • 我已经解决了我的问题。对于那些获得No default constructor 或@Autowired 的人已经找到了。确保您的构造函数没有默认值。
猜你喜欢
  • 1970-01-01
  • 2021-01-18
  • 2016-12-24
  • 1970-01-01
  • 1970-01-01
  • 2020-10-11
  • 2015-06-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多