2016-06-23 5 views
2

У меня есть некоторые бобы (нескольких типов, CDI, @Stateless и @Singleton бобы). Некоторые из полей должны вводиться из значений базы данных.Есть ли способ для повторного ввода/обновления инжектируемых полей бобов?

public class MyBean { 

    @Inject 
    @DbConfigValue(MyConfig.HOST) 
    String host; 
} 

Так что я добавил пользовательские @Qualifier (DbConfigValue), используемый Producer. Производитель считывает и кэширует значения конфигурации из базы данных и вводит их в bean-компоненты.

@Singleton 
@Lock(LockType.READ) 
public class Configuration { 

    @Produces 
    @Dependent 
    @DbConfigValue 
    public String getDbConfigValue(InjectionPoint point) { 
     // get key for the config-value from qualifier-annotation of the injected field 
     String key = point.getAnnotated().getAnnotation(DbConfigValue.class).value(); 
     // i have read+cached database config values in @PostConstruct before 
     return cachedConfigValues.get(key); 
    } 
} 

Это хорошо работает для первоначальной инжекционной/бобовой конструкции. Некоторые веб-учебные пособия предлагают такой подход.

Теперь, я думаю, разумно предположить, что значения конфигурации, если они хранятся в БД, могут меняться во время выполнения. Таким образом, всякий раз, когда администратор изменяет значение конфигурации базы данных, я в настоящее время запускаю CDI-событие.

Вопрос: есть ли способ повторно вставить значения в поля уже инициализированных экземпляров bean-экземпляров? Или инъекция всегда связана только с созданием экземпляра?

E.g. У меня было с. похожее на это в виду:

public class MyEventListener { 

    @Inject 
    BeanManager beanManager; 

    @Asynchronous 
    public void onDbConfigValueChangedEvent (@Observes(during = TransactionPhase.AFTER_SUCCESS) DbConfigValueChangedEvent event) { 
     try { 
      // could be filtered by custom qualifier: 
      Set<Bean<?>> beans = beanManager.getBeans(Object.class,new AnnotationLiteral<Any>() {}); 

      for (Bean<?> bean : beans) { 
       Set<InjectionPoint> points = bean.getInjectionPoints(); 
       // What now? javax.enterprise.inject.spi.Bean is the 
       // bean-representation only. 
       // Can I somehow resolve the actual bean-instances here? 
       // Then update Field via Reflection? 
      } 
     } 
     catch(Exception e){ 
      // ... 
     } 
    } 
} 

Я также считается DeltaSpike, который имеет некоторые методы для литья под контролем. Тем не менее, я только нашел методы для ввода в новые экземпляры bean или даже с новыми или null-CreationalContexts (beans not CDI-managed after)

Обратите внимание: я знаю, что могу решить этот конкретный прецедент путем введения конфигурации и явно получать текущие значения для каждого запроса, как это:

public class MyBean { 

    @Inject 
    Configuration config; 

    public void someMethod(){ 
     String host = config.getConfig(MyConfig.HOST); 
     // ... 
    } 
} 

Однако, я задаюсь вопросом о вопросе в целом: существует ли какая-либо поддержка повторной инъекции? Или, если нет, запрещают ли спецификации (CDI или Java EE)?

ответ

1

В зависимости от того, насколько быстрым/медленным является ваш дБ, это может быть дорого. Вероятно, вы можете использовать механизм кэширования в методе производителя. Плечо на Instance Механизмы впрыска, которые лениво загружают фактический инжектируемый компонент.

Ваш Производитель (Вероятно, используя на некоторых из кэш-памяти, чтобы избежать децибел вызывает все фолиант)

@Singleton 
@Lock(LockType.READ) 
public class Configuration { 

    @Produces 
    @RequestScoped //May fail if not in a request-context, but for ejb-calls, it is guaranteed to work as CDI has EJB Request Context 
    @DbConfigValue 
    public String getDbConfigValue(InjectionPoint point) { 
     // get key for the config-value from qualifier-annotation of the injected field 
     String key = point.getAnnotated().getAnnotation(DbConfigValue.class).value(); 
     // i have read+cached database config values in @PostConstruct before 
     return cachedConfigValues.get(key); 
    } 
} 

И точки впрыска:

@SessionScoped 
public class MyBean { 

    @Inject 
    @DbConfigValue(MyConfig.HOST) 
    private Instance<String> host; 

    public void doSomething() { 
     String myHost = host.get(); // of course will throw exception if value is failing. It will be resolved with every request. 
    } 
} 
+0

Thx, полезно, но не совсем то, что я хотел: это запрос на инъекцию (через 'Instance.get()') по каждому запросу (каждый вызов 'doSomething'). Поэтому он похож на мой последний фрагмент ('config.getConfig()'), хотя вам снова удалось применить метод Producer. Но я скорее хотел повторно вводить инъекцию только тогда, когда было запущено событие CDI. И спросил себя, можно ли повторно ввести из ** вне ** ('MyEventListener') ** в ** все запущенные экземпляры bean-экземпляров. – Ben

+0

В идеале производитель может сохранить значение в кеше, которое может быть обновлено в любое время (при его изменении только продюсер может прослушивать событие cdi и обновлять кеш), и обновление будет подхвачено всеми экземпляров. Reinjecting, imo просто не выглядит правильным в этом контексте – maress

+0

Да, значения кэшируются и обновляются только после изменения. Фактически, я даже уже изменил свой код на решение, подобное этому для этой конкретной проблемы. Однако, как упоминалось в этом вопросе, я сам спросил себя, есть ли поддержка для повторной инъекции в JavaEE/CDI. Просто из любопытства и для возможного использования в будущем. Итак, если вы говорите «не так в этом контексте», знаете ли вы о решениях для повторной инъекции (для разных контекстов)? – Ben

0

Там не никакой поддержки для повторной инъекции , CDI имеет статическую природу, что означает, что все решено во время загрузки и остается таким же после этого.

Он был разработан как таковой, и повторная инъекция (или любой другой динамический материал) не может быть введена, поскольку она разрушит всю структуру. Например, проверки бонусов выполняются во время загрузки, и это требует много времени. Повторная инъекция потребует повторной проверки.

Чтобы предложить решение проблемы:

Вы можете захотеть взглянуть на пользовательских областях, где вы можете управлять жизненным циклом сферы. Чтобы иметь область видимости, вам также необходимо иметь Context, который будет реализовывать эту область (то есть, где вы выполняете реализацию). И почему все это? Хорошо, если бы вы могли закончить жизненный цикл области наблюдения событий и создать новый, это также означало бы, что он снова запустит продюсера и создаст новую ссылку, в конечном счете вознаградив вас новым обновленным объектом.

Смежные вопросы