【问题标题】:CDI: Inject different bean in an EJB depending on the callerCDI:根据调用者在 EJB 中注入不同的 bean
【发布时间】:2014-08-13 12:06:44
【问题描述】:

我正在尝试在无状态 EJB 中注入一个 bean。但是,当从 ManagedBean 或 EJB 计时器调用 EJB 时,我希望该 bean 有所不同。

这是我在其中注入用户 bean 的 EJB:

MyEjb.java

@Stateless
class MyEjb{
    @Inject
    @CurrentContext
    private User user;

    public void foo(){
        System.out.println(user);
    }
}

这是一个使用 EJB 的 EJB 计时器:

TimerTest.java

@Singleton
@Startup
class TimerTest {

    @EJB
    private MyEjb myEjb;

    @Timeout
    public void doIt(Timer timer) {
        myEjb.foo();
    }   


    @Produces
    @CurrentContext
    public User produceCurrentUserInEjbTimer(){
        return new User("system");
    }
}

最后,使用 MyEjb 的 ManagedBean:

MyManagedBean.java

@ManagedBean
@SessionScoped
class MyManagedBean {
    @EJB
    private MyEjb myEjb;


    public void bar() {
        myEjb.foo();
    }


    @Produces
    @CurrentContext
    @RequestScoped
    public User produceCurrentUserInManagedBean(){
        return new User(FacesContext.getCurrentInstance().getExternalContext().getRemoteUser());
    }
}

当达到超时时,我希望 MyEbj 的 foo 方法使用由方法produceCurrentUserInEjbTimer 创建的系统用户。

当调用 ManagedBean 的 bar 方法时,我希望 MyEbj 的 foo 方法使用 FaceContext 的远程用户(由方法 createCurrentUserInManagedBean 创建)。

【问题讨论】:

  • 并且不能以用户为参数调用MyEjb#foo
  • 不,其实我也在拦截器中使用用户。

标签: jsf ejb cdi


【解决方案1】:

我宁愿只有一个生产者检查 FacesContext.getCurrentInstance() != null 是否然后调用适当的代码:

public User produceCurrentUser(){
        if(FacesContext.getCurrentInstance() != null){
            return new User(FacesContext.getCurrentInstance().getExternalContext().getRemoteUser());
        }
        else{
             return new User("system");
       }
    }

您也可以直接在计时器或 ManagedBean 上注入您的用户,然后使用 InjectionPoint 对象知道您的用户被注入到哪个类:

public User produceCurrentUser(InjectionPoint injectionPoint){
      System.out.println(injectionPoint.getBean());
}

您还应该使用@Named 和@javax.enterprise.context.SessionScoped,因为您的应用程序上有CDI 而不是@ManagedBean。

更新

我不确定是否有直接的方法来获取注入的上下文,可能会抛出 CDI 扩展,但我从未尝试过。

如何通过编程查找来获取上下文实例:

    @Stateless
class MyEjb{
    @Inject @Any Instance<User> userSource;

    public void foo(String context) // you should define contexts your self as jms, jsf ...
    {
// Every expected context will have a qualifier
      Annotation qualifier = context.equals("jsf") ?
      new JSFQualifier() : new JMSQualifier();
      User p = userSource.select(qualifier).get();
      System.out.println(user);
    }
}

这是你可以注入你的 EJB 并将上下文参数传递给 foo:

@Named
@SessionScoped
class MyManagedBean {
    @EJB
    private MyEjb myEjb;


    public void bar() {
        myEjb.foo("jsf");
    }
}

【讨论】:

  • 嗯,这是一个解决方案!但我希望让容器根据上下文(JSF、Timer、JMS、JAXRS、...)选择正确的生产者,没办法?
  • 我已经用其他选项更新了帖子,希望对您有所帮助。
  • 这与将用户对象作为参数传递相同......它不适用于拦截器。
  • 你预见到拦截器的用例是什么
  • 我将记录所有用户对名为 saveXXX 或 updateXXX 的方法的操作,以在 bean 上保存用户 ID
猜你喜欢
  • 1970-01-01
  • 2015-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-16
  • 2013-06-30
  • 1970-01-01
  • 2014-10-12
相关资源
最近更新 更多