Spring boot 依赖注入不适用于子类,值未在调用时初始化

问题描述 投票:0回答:1

我想向我的项目中的一些子类注入 som 依赖项,但是它并没有像我想象的那样工作......我正在使用 Spring Boot 3.0.4Java 17Kotlin 1.8 编写。 0

我的课程如下所示:

@Service
sealed class Integration {

  @Autowired lateinit var smsClient: SmsClient

  @Autowired lateinit var emailClient: EmailClient

  abstract val reference: UUID
  abstract val integrationType: IntegrationType
  abstract fun send(incomingMessage: String)
  abstract fun getContactPoints(): List<String>
}

@Schema(description = "Integration of sms notifications.", allOf = [Integration::class])
class SmsIntegration(
    override val reference: UUID = UUID.randomUUID(),
    override val integrationType: IntegrationType = IntegrationType.SMS_INTEGRATION,
    val countryCode: String,
    val phoneNumbers: List<String>,
) : Integration() {

  @PostConstruct
  override fun send(incomingMessage: String) {
    phoneNumbers.forEach { smsClient.postSms(SmsRequest(countryCode, it, incomingMessage)) }
  }
  override fun getContactPoints(): List<String> = this.phoneNumbers

  fun copy(phoneNumbers: List<String>): SmsIntegration =
      SmsIntegration(
          reference = this.reference, countryCode = this.countryCode, phoneNumbers = phoneNumbers)
}

@Schema(description = "Integration of email notifications.", allOf = [Integration::class])
class EmailIntegration(
    override val reference: UUID = UUID.randomUUID(),
    override val integrationType: IntegrationType = IntegrationType.EMAIL_INTEGRATION,
    val emails: List<String>,
    val subject: String,
) : Integration() {

  @PostConstruct
  override fun send(incomingMessage: String) {
    val emailAddresses: List<EmailAddress> = emails.map { EmailAddress(email = it) }
    val email =
        Email(
            from = EmailAddress(email = "[email protected]"),
            to = emailAddresses,
            subject = subject,
            body = incomingMessage)

    emailClient.sendEmail(email)
  }
  override fun getContactPoints(): List<String> = this.emails

  fun copy(emails: List<String>): EmailIntegration =
      EmailIntegration(reference = this.reference, subject = this.subject, emails = emails)
}

@Schema(description = "Integration of slack notifications.", allOf = [Integration::class])
class SlackIntegration(
    override val reference: UUID = UUID.randomUUID(),
    override val integrationType: IntegrationType = IntegrationType.SLACK_INTEGRATION,
    val channelIds: List<String>
) : Integration() {

  fun copy(channelIds: List<String>): SlackIntegration =
      SlackIntegration(reference = this.reference, channelIds = channelIds)

  @PostConstruct
  override fun send(incomingMessage: String) {
    channelIds.forEach { SlackBot.sendMessage(channelId = it, message = incomingMessage) }
  }

  override fun getContactPoints(): List<String> = this.channelIds
}

如您所见,我的 Integration 课程中有两个自动连接的客户端,一个用于短信,一个用于电子邮件。我宁愿将它们放在单独的类中,但是我不想在创建这些类时在代码周围的构造函数中传递 emailClients 和 smsclients,因此我选择将它们放在 Integration 类中。但是,在 SmsIntegrationEmailIntegration 类中调用 send() 函数时,它们没有被初始化。

我觉得关于 spring boot 中的依赖注入,我的代码结构很糟糕。仅使用 slackBot 就很好,也很容易,因为它是一个单例,但是随着添加的依赖项,它变得一团糟..

感谢任何帮助重组或完成这项工作的人。

spring spring-boot kotlin inheritance dependency-injection
1个回答
0
投票

我不确定

@Schema
注释, 我假设它使您的课程成为组件

当你在做继承和Autowired时,一定要在setter上设置注释

@set:Autowired
,在这种情况下你甚至不需要用服务标记你的超类,

我认为在超类中获取实现是一个坏主意,正如评论中所提到的

@PostConstruct
并不是为了这个(我认为你想在这种情况下使用
@EventListener

这是另一种方法:

// Integration.kt
interface Message
interface Integration {
    fun send(message: Message)
    fun supports(message: Message): Boolean
}

// SMSIntegration.kt
class SMS(val phoneNumber: String) : Message
@Service
class IntegrationSMS : Integration {
    override fun send(message: Message) {
        message as SMS
        // send it
    }

    // implements send(SMS)
    override fun supports(message: Message) = message is SMS
}

// SlackIntegration.kt
class SlackMessage : Message
@Service
class IntegrationSlack : Integration {
    override fun send(message: Message) {
        message as SlackMessage
    }

    // implements send(SlackMessage)
    override fun supports(message: Message) = message is SlackMessage
}


// IntegrationManager.kt
@Service
class IntegrationManager(@Autowired  val integrators: List<Integration> ){

   @EventListener
   fun sendMessage(message: Message){
       for(integration in integrators)
          if(integration.supports(message)
             integration.send(message)
   }

}

现在您可以在代码中的任何位置执行以下操作:


@Service
class SomewhereElse( val publisher: ApplicationEventPublisher){

   fun doSomethingAndSendSMS(){
     ... 
     publisher.publish(SMS("1234"))
   }

   fun doSomethingAndSendSlackMessage(){
     ... 
     publisher.publish(SlackMessage())
   }

}

如果你搁置

@EventListener
你可以直接调用
IntegrationManager.sendMessage
这是SpringSecurity使用的实际方法(据我所知在servlet中)
AuthenticationProvider
AuthenticationManager
以及几个
AuthenticationTokens

© www.soinside.com 2019 - 2024. All rights reserved.