【问题标题】:How to use spring annotations like @Autowired in kotlin?如何在kotlin中使用@Autowired之类的spring注解?
【发布时间】:2016-05-30 12:15:26
【问题描述】:

是否可以在 Kotlin 中执行类似以下操作?

@Autowired
internal var mongoTemplate: MongoTemplate

@Autowired
internal var solrClient: SolrClient

【问题讨论】:

  • 你试过了吗?为了更具建设性……有一个完整的Spring Boot template,答案肯定是“是”。
  • @mabi 谢谢你的教程链接:)

标签: spring kotlin


【解决方案1】:

在 Spring 中进行依赖注入的推荐方法是构造函数注入:

@Component
class YourBean(
    private val mongoTemplate: MongoTemplate, 
    private val solrClient: SolrClient
) {
  // code
}

在 Spring 4.3 之前的构造函数应该使用Autowired 显式注释:

@Component
class YourBean @Autowired constructor(
    private val mongoTemplate: MongoTemplate, 
    private val solrClient: SolrClient
) {
  // code
}

在极少数情况下,您可能喜欢使用字段注入,您可以在lateinit 的帮助下做到这一点:

@Component
class YourBean {

    @Autowired
    private lateinit var mongoTemplate: MongoTemplate

    @Autowired
    private lateinit var solrClient: SolrClient
}

构造函数注入在 bean 创建时检查所有依赖项,并且所有注入的字段都是val,另一方面,lateinit 注入的字段只能是var,并且运行时开销很小。而用构造函数测试类,你不需要反射。

链接:

  1. Documentation on lateinit
  2. Documentation on constructors
  3. Developing Spring Boot applications with Kotlin

【讨论】:

  • 我可以将@Autowired 与主要构造函数参数一起使用吗?
  • 当然,我在第二个和第三个示例中使用主构造函数进行注入。
  • 你也可以通过setter添加autowired吗?
  • @IRus,您在示例中使用了私有 val,但我想说的是,我在 Internet 上找到的所有示例中,有 80% 的 Kotlin 都没有“私有”修饰符。这将被视为 Java 中的代码异味。这是什么原因?你碰巧知道吗?我什至认为它值得一个单独的问题。
  • @yuranos87 假设开发人员在FooBean 中注入YourBean,以防YourBean 依赖项是公共的(Kotlin 中的默认修饰符)开发人员可以在FooBean 中使用YourBean 依赖项( yourBean.mongoTemplate)。但这不应该被允许,因为YourBean 依赖不是他的公共合同,它只是实现细节(在大多数情况下)。相反,FooBean 应该在自己的构造函数中定义自己的依赖项。
【解决方案2】:

是的,在 Kotlin 中支持 Java 注释,主要与在 Java 中一样。 一个问题是主构造函数上的注释需要显式的“构造函数”关键字:

来自https://kotlinlang.org/docs/reference/annotations.html

如果需要对类的主构造函数进行注解,需要在构造函数声明中添加constructor关键字,并在其前添加注解:

class Foo @Inject constructor(dependency: MyDependency) {
  // ...
}

【讨论】:

    【解决方案3】:

    您还可以通过构造函数自动装配依赖项。请记住使用 @Configuration, @Component, @Service 等注释您的依赖项

    import org.springframework.stereotype.Component
    
    @Component
    class Foo (private val dependency: MyDependency) {
        //...
    }
    

    【讨论】:

      【解决方案4】:

      这样

      @Component class Girl( @Autowired var outfit: Outfit)
      

      【讨论】:

      • 不需要自动接线
      • 这里的constructor关键字在哪里?
      • @vigamage Kotlin 不需要 constructor 关键字作为主构造函数。
      【解决方案5】:

      如果您想要属性注入但不喜欢lateinit var,这是我使用property delegate 的解决方案:

      private lateinit var ctx: ApplicationContext
      
      @Component
      private class CtxVarConfigurer : ApplicationContextAware {
          override fun setApplicationContext(context: ApplicationContext) {
              ctx = context
          }
      }
      
      inline fun <reified T : Any> autowired(name: String? = null) = Autowired(T::class.java, name)
      
      class Autowired<T : Any>(private val javaType: Class<T>, private val name: String?) {
      
          private val value by lazy {
              if (name == null) {
                  ctx.getBean(javaType)
              } else {
                  ctx.getBean(name, javaType)
              }
          }
      
          operator fun getValue(thisRef: Any?, property: KProperty<*>): T = value
      
      }
      

      然后你可以使用更好的by委托语法:

      @Service
      class MyService {
      
          private val serviceToBeInjected: ServiceA by autowired()
      
          private val ambiguousBean: AmbiguousService by autowired("qualifier")
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-07
        • 1970-01-01
        • 2011-04-01
        • 2012-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多