在使用 Quarkus 进行本地开发期间注入不同的 Bean

Jim*_*ton 4 cdi quarkus

使用 Spring 和 Micronaut,有非常简洁的方法可以根据应用程序运行的环境/配置文件来注入不同的 bean。我正在尝试对 Quarkus 做同样的事情。

我读过这篇文章: https: //quarkus.io/blog/quarkus-dependency-injection/。这个 StackOverflow 帖子中提到了这个过程:How can I override a CDI bean in Quarkus for test? 。最后一篇文章说,“在测试目录中创建 bean”。

我的问题略有不同。我想在“开发”时注入一个bean。在生产中,我想注入默认的 bean。从文档中,我看不出有什么方法可以让应用程序做出这种区分。

如果我有一个像这样的默认类:

@DefaultBean
@ApplicationScoped
class ProdProvider : SomeProvider {}
Run Code Online (Sandbox Code Playgroud)

我想像这样覆盖它:

@Alternative
@Priority(1)
class DevProvider : SomeProvider {}
Run Code Online (Sandbox Code Playgroud)

我怎样才能只在开发模式下发生这种情况?

在一种情况下,我有一个凭据提供程序类,用于在本地开发时设置 Google 的 PubSub 模拟器。在生产中,我使用一个实现相同接口的类,但它是一个真正的凭据提供程序。导致我问这个问题的特殊情况是一个实现一种方法的类:

@ApplicationScoped
class VaultLoginJwtProvider : LoginJwtProvider {
  @ConfigProperty(name = "vault.tokenPath")
  private val jwtPath: String? = null

  companion object {
    val logger: Logger = LoggerFactory.getLogger("VaultTokenProvider")
  }

  override fun getLoginJwt(): Optional<String> {
    logger.info("Using Vault Login JWT")

    return try {
      Optional.of(String(Files.readAllBytes(Paths.get(jwtPath))).trim { it <= ' ' })
    } catch (e: Exception) {
      logger.error("Could not read vault token at $jwtPath")
      logger.error(e.printStackTrace().toString())
      Optional.empty()
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

该类通过构造函数注入注入到另一个类中:

@Singleton
class JwtServiceImpl(
  @RestClient val vaultClient: VaultClient,
  @Inject val loginJwtProvider: LoginJwtProvider
) {
  private var serviceJwt: String? = null

  companion object {
    val logger: Logger = LoggerFactory.getLogger("JwtServiceImpl")
  }

  private fun getLoginToken(): String? {
    val vaultLogin = VaultLogin(
      role = "user-service",
      jwt = loginJwtProvider.getLoginJwt().get()
    )

    val loginResponse = vaultClient.login(vaultLogin)

    return loginResponse.auth.clientToken
  }
}
Run Code Online (Sandbox Code Playgroud)

我想在开发过程中注入更多的“模拟”类,只返回静态字符串。我可以使用ProfileManager.getActiveProfile(),但这让我将开发问题融入到我的逻辑中。我觉得这在我编译的生产代码中没有任何地位。

在 Micronaut 中可以通过使用注释来实现这一点@Requires(env = ["dev", "test"])。我确实简要地了解了使用@Produces,但 Oracle EE 文档对我来说似乎有点难以掌握。如果这是解决方案,我会深入研究。

小智 9

如果其他人遇到这种情况,请按以下方法操作:https ://quarkus.io/guides/cdi-reference#enabling-beans-for-quarkus-build-profile

例如:

import javax.enterprise.inject.Produces;

import com.oi1p.common.EmailSender;
import com.oi1p.common.ErrorEmailSender;
import com.oi1p.common.LogOnlyEmailSender;

import io.quarkus.arc.DefaultBean;
import io.quarkus.arc.profile.IfBuildProfile;

@ApplicationScoped
public class Producers {

  @Produces
  @IfBuildProfile("dev")
  public EmailSender logOnlyEmailSender() {
    return new LogOnlyEmailSender();
  }

  @Produces
  @DefaultBean
  public EmailSender errorEmailSender() {
    // TODO: implement a real email sender.  This one explodes when poked.
    return new ErrorEmailSender();
  }

}
Run Code Online (Sandbox Code Playgroud)