在使用 Quarkus 进行本地开发期间注入不同的 bean
Injecting a different bean during local development with Quarkus
使用 Spring 和 Micronaut,有非常简洁的方法来注入不同的 bean,具体取决于 environment/profile 应用程序 运行 所在的内容。我正在尝试做同样的事情与夸尔库斯。
我读过这个 post:https://quarkus.io/blog/quarkus-dependency-injection/. And the process is alluded to in this Whosebug post: 。最后一个 post 表示 "create bean in test directory"。
我的问题略有不同。我想在 "development" 中注入一个 bean。在生产中,我想要注入默认 bean。从文档中,我看不到让应用程序做出这种区分的方法。
如果我有这样的默认 class:
@DefaultBean
@ApplicationScoped
class ProdProvider : SomeProvider {}
我想像这样覆盖它:
@Alternative
@Priority(1)
class DevProvider : SomeProvider {}
我怎样才能让它只在开发模式下发生?
在一个案例中,我有一个凭证提供程序 class,它在本地开发时设置了 Google 的 PubSub 模拟器。在生产中,我使用 class 实现相同的接口,但它是一个真正的凭证提供者。导致我问这个问题的特殊情况是 class 实现了一种方法:
@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()
}
}
}
通过构造函数注入将 class 注入另一个 class:
@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
}
}
我想在开发中注入更多 "mock" class 只是 returns 静态字符串。我可以使用 ProfileManager.getActiveProfile()
,但这让我将开发问题混入了我的逻辑中。而且我觉得这在我编译的生产代码中没有任何位置。
这可以在 Micronaut 中使用注解 @Requires(env = ["dev", "test"])
实现。我确实简要地查看了使用 @Produces
,但 Oracle EE 文档对我来说似乎有点难以掌握。如果那是解决方案,我会深入研究。
我的解决方案是在 @javax.ws.rs.ext.Provider. Not as elegant as Micronaut @Requires 中自行创建最终的 bean,但它确实有效。
请注意 SomeProvider 的实例不是 "bean",您必须自己关心生命周期(依赖注入、PostConstruct、无 PreDestroy、.. .).
org.acme.SomeProvider.java
package org.acme;
import javax.enterprise.context.ApplicationScoped;
public interface SomeProvider {
void providerMethod();
@ApplicationScoped
class ProdProviderRequirement {
void foo() {}
}
class ProdProvider implements SomeProvider {
private final ProdProviderRequirement prodProviderRequirement;
ProdProvider(final ProdProviderRequirement prodProviderRequirement) {
this.prodProviderRequirement = prodProviderRequirement;
}
@Override
public void providerMethod() {
prodProviderRequirement.foo();
}
}
class DevProvider implements SomeProvider {
@Override
public void providerMethod() {}
}
}
org.acme.SomeProviderFactory.java
package org.acme;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.ws.rs.ext.Provider;
import org.acme.SomeProvider.DevProvider;
import org.acme.SomeProvider.ProdProvider;
import org.acme.SomeProvider.ProdProviderRequirement;
@Provider
class SomeProviderFactory {
SomeProvider someProvider;
@Inject
SomeProviderFactory(final ProdProviderRequirement prodProviderRequirement) {
final var someCondition = true;
someProvider = someCondition ? new DevProvider() : new ProdProvider(prodProviderRequirement);
}
@Produces
@ApplicationScoped
SomeProvider someProvider() {
return someProvider;
}
}
如果其他人遇到此问题,请按以下步骤操作: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();
}
}
使用 Spring 和 Micronaut,有非常简洁的方法来注入不同的 bean,具体取决于 environment/profile 应用程序 运行 所在的内容。我正在尝试做同样的事情与夸尔库斯。
我读过这个 post:https://quarkus.io/blog/quarkus-dependency-injection/. And the process is alluded to in this Whosebug post:
我的问题略有不同。我想在 "development" 中注入一个 bean。在生产中,我想要注入默认 bean。从文档中,我看不到让应用程序做出这种区分的方法。
如果我有这样的默认 class:
@DefaultBean
@ApplicationScoped
class ProdProvider : SomeProvider {}
我想像这样覆盖它:
@Alternative
@Priority(1)
class DevProvider : SomeProvider {}
我怎样才能让它只在开发模式下发生?
在一个案例中,我有一个凭证提供程序 class,它在本地开发时设置了 Google 的 PubSub 模拟器。在生产中,我使用 class 实现相同的接口,但它是一个真正的凭证提供者。导致我问这个问题的特殊情况是 class 实现了一种方法:
@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()
}
}
}
通过构造函数注入将 class 注入另一个 class:
@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
}
}
我想在开发中注入更多 "mock" class 只是 returns 静态字符串。我可以使用 ProfileManager.getActiveProfile()
,但这让我将开发问题混入了我的逻辑中。而且我觉得这在我编译的生产代码中没有任何位置。
这可以在 Micronaut 中使用注解 @Requires(env = ["dev", "test"])
实现。我确实简要地查看了使用 @Produces
,但 Oracle EE 文档对我来说似乎有点难以掌握。如果那是解决方案,我会深入研究。
我的解决方案是在 @javax.ws.rs.ext.Provider. Not as elegant as Micronaut @Requires 中自行创建最终的 bean,但它确实有效。
请注意 SomeProvider 的实例不是 "bean",您必须自己关心生命周期(依赖注入、PostConstruct、无 PreDestroy、.. .).
org.acme.SomeProvider.java
package org.acme;
import javax.enterprise.context.ApplicationScoped;
public interface SomeProvider {
void providerMethod();
@ApplicationScoped
class ProdProviderRequirement {
void foo() {}
}
class ProdProvider implements SomeProvider {
private final ProdProviderRequirement prodProviderRequirement;
ProdProvider(final ProdProviderRequirement prodProviderRequirement) {
this.prodProviderRequirement = prodProviderRequirement;
}
@Override
public void providerMethod() {
prodProviderRequirement.foo();
}
}
class DevProvider implements SomeProvider {
@Override
public void providerMethod() {}
}
}
org.acme.SomeProviderFactory.java
package org.acme;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.ws.rs.ext.Provider;
import org.acme.SomeProvider.DevProvider;
import org.acme.SomeProvider.ProdProvider;
import org.acme.SomeProvider.ProdProviderRequirement;
@Provider
class SomeProviderFactory {
SomeProvider someProvider;
@Inject
SomeProviderFactory(final ProdProviderRequirement prodProviderRequirement) {
final var someCondition = true;
someProvider = someCondition ? new DevProvider() : new ProdProvider(prodProviderRequirement);
}
@Produces
@ApplicationScoped
SomeProvider someProvider() {
return someProvider;
}
}
如果其他人遇到此问题,请按以下步骤操作: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();
}
}