Основная проблема заключается в том, что ConfigSource получает экземпляр очень рано, когда BeanManager недоступен. Даже поиск JNDI не работает в этот момент времени. Таким образом, мне нужно отложить инъекцию/поиск.
Что я сделал сейчас, добавляет статический логический элемент в мой конфигурационный источник, который я устанавливаю вручную. У нас есть InitializerService, который гарантирует правильную настройку системы. В конце процесса инициализации я вызываю allowInitialization()
, чтобы сообщить источнику конфигурации, что данный компонент теперь можно вводить. В следующий раз, когда спросит 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);
}
}
}
У меня есть фасоль с запросом, содержащая все мои переменные конфигурации для безопасного доступа типа.
@RequestScoped
public class Configuration {
@Inject
@ConfigProperty(name = "myProperty")
private String myProperty;
@Inject
@ConfigProperty(name = "myProperty2")
private String myProperty2;
....
}
При вводе класса конфигурации в другом компоненте каждый 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. Тем не менее, у нас есть настройка нескольких арендаторов, и параметры должны быть разрешены для каждого запроса.
Как вы можете видеть, это немного хакерство, потому что нам нужно явно указать ConfigSource, когда ему разрешено правильно создавать экземпляры (вставлять компонент).
Я бы предпочел стандартизованный решение от DeltaSpike для использования CDI в ConfigSource. Если у вас есть идея о том, как правильно это понять, сообщите мне.
Вы все же можете улучшить 'initIfNecessary()' - на данный момент это работает скорее как 'initIfPossible()', т.е. поля не получают слишком скоро, но они вводятся при каждом вызове 'getPropertyValue()' , –
Отступ 1.8 будет фиксировать это. –