2015-03-13 1 views
2

Я работаю над приложением Java EE 7 в контейнере Wildfly 8.2, который содержит некоторые объекты, которые существуют в двух источниках данных. Пример:Передача квалификатора CDI в поле ввода

У меня есть баночка с Setting лица:

@Entity 
public class Setting { 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 

    @NotNull 
    private String name; 
    private String value; 

    getters/setters... 
} 

и боб, который имеет несколько методов для получения и сохранения этой сущности из базы данных с помощью критериев запроса:

@Stateless 
public class SettingRepository { 
    @Inject 
    private Logger logger; 

    @Inject 
    private EntityManager entityManager; 

    public Setting findByName(@NotNull String name) { 
     logger.trace("Getting setting by name: name=" + name); 
     CriteriaBuilder cb = entityManager.getCriteriaBuilder(); 
     CriteriaQuery<Setting> cq = cb.createQuery(Setting.class); 
     Root<Setting> table = cq.from(Setting.class); 
     cq.where(cb.equal(table.get(Setting_.name), name)); 

     TypedQuery<Setting> query = entityManager.createQuery(cq); 
     List<Setting> results = query.getResultList(); 
     Setting setting = null; 

     if (results.size() > 0) 
      setting = results.get(0); 

     logger.trace("Got setting: " + setting); 
     return setting; 
    } 

    ... 
} 

I wan't предоставить EntityManager и Logger экземпляров через @Producer в приложении, которое включает эту банку в classpath следующим образом:

@Produces @DataSource1 @PersistenceContext(unitName = "pu1") 
private EntityManager entityManager1; 

@Produces @DataSource2 @PersistenceContext(unitName = "pu2") 
private EntityManager entityManager2; 

@Produces 
private Logger produceLogger(InjectionPoint injectionPoint) { 
    return LogManager.getLogger(injectionPoint.getMember().getDeclaringClass().getName()); 
} 

Есть ли способ сконфигурировать SettingRepository в точке инъекции и указать ему, чтобы использовать конкретный менеджер объектов (или @DataSource2)?

Подобно этому:

@Inject @DataSource1 
private SettingRepository settingRepository; 

ответ

0

Маршрут я решил взять это один:

Я создал спецификатор

@Qualifier 
@Retention(RUNTIME) 
@Target({ METHOD, FIELD, PARAMETER }) 
public @interface DataSource { 
    @Nonbinding DataSourceName value() default DataSourceName.D1; 
} 

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

И DataSourceName перечисление, которое просто перечисляет все источники данных:

public enum DataSourceName { 
    D1, D2 
} 

Я также изменил SettingRepository реализацию и добавил публичный метод инициализации.

@Dependent 
public class SettingRepository { 
    @Inject 
    private Logger logger; 

    private EntityManager entityManager; 

    public void initialize(EntityManager entityManager) { 
     this.entityManager = entityManager; 
    } 

    ... 
} 

Обратите внимание, что EntityManager больше не вводится контейнером.

Когда я wan't впрыснуть SettingRepository, я просто украсить его с этим классификатором так:

@Inject @DataSource(DataSourceName.D1) 
private SettingRepository settingRepository; 

Все, что мне нужно сейчас, чтобы определить производителя для SettingRepository:

@Stateless 
public class TestResourcesForSettings { 
    @PersistenceContext(unitName = "pu1") 
    private EntityManager entityManager1; 

    @PersistenceContext(unitName = "pu2") 
    private EntityManager entityManager2; 

    @Inject 
    private SettingRepository settingRepository; 

    @Produces @DataSource 
    public SettingRepository produceSettingRepository(InjectionPoint ip) { 
     DataSource annotation = ip.getAnnotated().getAnnotation(DataSource.class); 

     if (annotation.value() == DataSourceName.D1) 
      settingRepository.initialize(entityManager1); 
     else if (annotation.value() == DataSourceName.D2) 
      settingRepository.initialize(entityManager2); 

     return settingRepository; 
    } 

И voila, я могу использовать два источника данных с одной реализацией репозитория (примечание: источники данных должны быть XA). Если кто-нибудь найдет какие-либо проблемы с этим выбором, пожалуйста, скажите мне.

0

Да!

На самом деле вы сделали всю тяжелую работу, уже, насколько методы производителей и классификаторы обеспокоены :-) Все, что вам нужно сделать, это использовать спецификатор (@ DataSource1 и т.д.) на нагнетаемом экземпляре EntityManager

@Inject @DataSource1 
private EntityManager entityManager; 

Это обеспечит, чтобы контейнер объекта JPA, прикрепленный к модулю постоянной нагрузки «pu1», был введен контейнером.

+2

Спасибо, но в первый раз, когда я знаю, какой источник данных мне нужен, находится в точке инсталляции 'SettingsRepository', а не в точке интуиции EntityManager. Поэтому мне было интересно, есть ли способ «передать» квалификаторы от родительской точки инъекции («НастройкиRepository») до точки инъекции ребенка («EntityManager») или лучше использовать параметры для каждого метода. – scetix