主要问题是,当 BeanManager 尚不可用时,ConfigSource 很早就被实例化了。即使是 JNDI 查找在那个时间点也不起作用。因此,我需要延迟注入/查找。
我现在所做的是向我的配置源添加一个静态布尔值,这是我手动设置的。我们有一个 InitializerService 来确保系统设置正确。在初始化过程结束时,我调用allowInitialization()
以告诉配置源,该 bean 现在是可注入的。下次询问 ConfigSource 时,它将能够使用BeanProvider.injectFields
.
public class DatabaseConfigSource implements ConfigSource {
private static boolean allowInit;
@Inject
private ConfigParameterProvider configParameterProvider;
@Override
public int getOrdinal() {
return 500;
}
@Override
public String getPropertyValue(String key) {
initIfNecessary();
if (configParameterProvider == null) {
return null;
}
return configParameterProvider.getProperty(key);
}
public static void allowInitialization() {
allowInit = true;
}
private void initIfNecessary() {
if (allowInit) {
BeanProvider.injectFields(this);
}
}
}
我有一个请求范围的 bean,它包含我所有的配置变量以进行类型安全访问。
@RequestScoped
public class Configuration {
@Inject
@ConfigProperty(name = "myProperty")
private String myProperty;
@Inject
@ConfigProperty(name = "myProperty2")
private String myProperty2;
....
}
当在不同的 bean 中注入 Configuration 类时,每个 ConfigProperty 都会被解析。由于我的自定义 DatabaseConfigSource 具有最高序数 (500),因此它将首先用于属性解析。如果找不到该属性,它会将解析委托给下一个 ConfigSource。
对于每个 ConfigProperty,getPropertyValue
都会调用 DatabaseConfigSource 中的函数。由于我不想从数据库中检索每个配置属性的参数,因此我将配置属性解析移至请求范围的 bean。
@RequestScoped
public class ConfigParameterProvider {
@Inject
private ConfigParameterDao configParameterDao;
private Map<String, String> configParameters = new HashMap<>();
@PostConstruct
public void init() {
List<ConfigParameter> configParams = configParameterDao.findAll();
configParameters = configParams.stream()
.collect(toMap(ConfigParameter::getId, ConfigParameter::getValue));
}
public String getProperty(String key) {
return configParameters.get(key);
}
}
我可以肯定将请求范围的 ConfigParameterProvider 更改为 ApplicationScoped。但是,我们有一个多租户设置,并且需要根据请求解析参数。
如您所见,这有点 hacky,因为我们需要明确告诉 ConfigSource,何时允许正确实例化(注入 bean)。
我更喜欢 DeltaSpike 的标准化解决方案,以便在 ConfigSource 中使用 CDI。如果您对如何正确实现这一点有任何想法,请告诉我。