Inject @EJB bean на основе условий

Вопрос с новичком: есть ли в любом случае, что я могу вставлять разные beans на основе условия, которое я задал в файле свойств. Вот чего я хочу достичь:

Я установил некоторое значение в файле свойств. Если это правда, тогда я хочу

  public class MyClass{
    @EJB
    private MyBean bean;
  }

если он ложный, то

public class MyClass{
  @EJB
  private MyBean2 bean2;
 }

Это выполнимо?

Ответ 1

Как сказал Гонсало, вам сначала необходимо указать общий интерфейс bean, если вы хотите объявить его как поле класса и использовать его различные реализации.

Кроме того, я думаю, вы могли бы достичь этого более элегантно, используя метод CDI @Produces; то есть между этими линиями:

@Singleton
@Startup
public class Configuration {

    private boolean someCondition;

    @PostConstruct
    private void init() {
        someCondition = ... // get a value from DB, JMS, XML, etc.
    } 

    @EJB(lookup="java:comp/env/myParticularBean")
    MyBean myBean1;

    @EJB(beanName="anotherTypeOfBeanInjectedByName")
    MyBean myBean2;

    @Produces
    public MyBean produceMyBean() {
        if (someCondition)
            return myBean1;
        } else {
            return myBean2;
        }
    }
}

Затем в вашем коде вы можете просто использовать:

@Inject
MyBean myBean;

и соответствующий bean, основанный на вашем условии, будет введен для вас.

Если вам не нужно поле на уровне класса, вы можете использовать старый путь и находить EJB в JNDI - таким образом вы можете управлять тем, какой тип и какой bean должен быть размещен и использован.

EDIT: Я добавил аннотированный beans @EJB, чтобы показать, откуда могут появиться экземпляры myBean1 и myBean2.

В этом примере показано, что вы можете иметь одно, единственное место, где вы определяете все свои зависимости от разных реализаций EJB и других компонентов. На этом примере это можно реализовать как одноэлементный EJB с полями @EJB, поля @PersistenceContext и т.д.

Вместо того, чтобы делать это в представленном виде, вы можете изменить return myBean1 на нечто вроде return context.lookup("JNDI_NAMESPACE_COORDINATES"), где context является экземпляром InitialContext.

Надеюсь, что это станет более ясным.

Ответ 2

Я не думаю, что вы можете изменить тип вводимого bean. Я бы сказал, что это ограничение Java, поскольку это строго типизированный язык:)

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

@Local
public interface MyBean {
}

@Stateless
public class MyBeanImpl1 implements MyBean {
}

@Stateless
public class MyBeanImpl2 implements MyBean {
}

Тогда вы могли бы сделать:

public MyClass {

@EJB(beanName="MyBeanImpl1")
MyBean myBean;

}

или

public MyClass {

@EJB(beanName="MyBeanImpl2")
MyBean myBean;

}

В зависимости от реализации, которую вы хотите ввести.