Перезагрузка контекста CDI во время выполнения - PullRequest
1 голос
/ 26 февраля 2020

У меня есть приложение на основе CDI. Во время выполнения мое приложение генерирует пользовательское событие, которое вызывает перезагрузку компонента. Перезагрузка bean означает go через все bean-компоненты и повторно инициализирует уже введенные bean-компоненты. Реинициализация должна учитывать зависимости bean-компонентов. Например:

class BeanA {

 String url;

 @PostConstruct
 void init(){
  url = UrlFactory.getNewUrl()
 }
}

class BeanB {

 @Inject
 BeanA beanA;

 @PostConstruct
 void init(){
  url = beanA.getUrl();
  doSomethingWith(url);
 }

Следовательно, когда наступает событие, BeanA и BeanB должны быть повторно инициализированы в строгом порядке, поэтому во время повторной инициализации BeanB BeanB уже знает о новом URL, инициализированном в BeanA. Можно ли это сделать во время выполнения, используя уже существующие инструменты в CDI (что-то вроде Spring: AutowireCapableBeanFactory)? Я обнаружил, что EJB уже имеет аннотацию @DependsOn, способную формировать порядок бинов во время запуска приложения.

Самое грубое силовое решение, которое я придумал, - это прослушивание одного из событий CDI во время запуска приложения, сбор всех bean-компонентов и построение графа зависимостей, а также во время перезагрузки go через этот граф и повторная инициализация. Боюсь, я не знаю о многих подводных камнях, с которыми я мог бы столкнуться (например, циклические c зависимости, ленивая инициализация (в этом случае это может вообще не сработать) и многих других, о которых я не знаю, потому что Я не очень хорошо понимаю, как работает контейнер CDI внутри.

1 Ответ

1 голос
/ 27 февраля 2020

Сначала создайте метод-производитель, который @Produces будет иметь String -типовое url значение (возможно, создайте аннотацию квалификатора @URL для дальнейшей его идентификации). Произведите это в @Dependent объеме. Что-то вроде:

@Produces @Dependent @URL private static final String produceUrl() {
  return UrlFactory.getNewUrl();
}

Теперь, где бы кто-нибудь ни делал @Inject @URL private String url, он получит новое String представление URL-адреса от вашего UrlFactory.

Что еще важнее, в любое время, когда кто-то это сделает @Inject @URL private Provider<String> urlProvider; они получат Provider, чей метод get() при вызове вернет самое последнее и наибольшее значение URL.

Это может быть все, что вам нужно, если вы посмотрите на него правильно.

Если это не все, что вам нужно, то заставьте BeanA сделать это:

@Inject
@URL
private Provider<String> urlProvider;

… и затем в его (опущенном выше) getUrl() методе сделать это:

public String getUrl() {
  return this.urlProvider.get();
}

Каждый раз вы будете получать новый String.

Если вы сделали , то , тогда вы можете просто добавить BeanA в свой метод наблюдателя и получить его передал вам:

private static final void onEvent(@Observes final YourEvent event, final BeanA beanA) {
  final String url = beanA.getUrl(); // latest and greatest      
}
...