在 SystemEventListener 中注入 CDI 托管 bean

Inject CDI managed bean in SystemEventListener

我已经使用 How to disable elements from within a ViewHandler after jsf has embedded the composite component? 的答案以编程方式禁用所有形式的所有组件。 SystemEventListener 捕获并禁用所有组件。

我想补充的是从 CDI bean 获取一些逻辑。看来我不能 @Inject SystemEventListener 中的 CDI bean。有没有其他机制可以从 CDI bean 获取逻辑?我有很多组件,将 disabled="#{bean.disabled}" 添加到所有组件会非常耗时。据我了解,这是 "batch disable" 的正确方法,或者我在这里严重错误?

您似乎还没有使用 JSF 2.2。从那个版本开始,许多 JSF 工件都符合 CDI 注入的条件,包括 SystemEventListener 个实例。另见 What's new in JSF 2.2? - Issue 763。如果您在支持 Servlet 3.0 的容器上使用 运行 JSF 2.0/2.1,那么升级到 JSF 2.2 应该是最简单的。

如果您由于某种原因无法升级,那么您始终可以通过 JNDI 以编程方式获取 CDI 托管 bean。 CDI BeanManager 实例在 JNDI 名称 java:comp/BeanManager 处可用。拿到手后,使用下面的 getReference() 实用方法获取感兴趣的参考。

public static <T> T getReference(BeanManager beanManager, Class<T> beanClass) {
    Bean<T> bean = resolve(beanManager, beanClass);
    return (bean != null) ? getReference(beanManager, bean) : null;
}

public static <T> Bean<T> resolve(BeanManager beanManager, Class<T> beanClass) {
    Set<Bean<?>> beans = beanManager.getBeans(beanClass);

    for (Bean<?> bean : beans) {
        if (bean.getBeanClass() == beanClass) {
            return (Bean<T>) beanManager.resolve(Collections.<Bean<?>>singleton(bean));
        }
    }

    return (Bean<T>) beanManager.resolve(beans);
}

public static <T> T getReference(BeanManager beanManager, Bean<T> bean) {
    return (T) beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));
}

(源代码来自OmniFaces Beans/BeansLocal

所以,简而言之:

BeanManager beanManager = (BeanManager) new InitialContext().lookup("java:comp/BeanManager");
YourBean yourBean = getReference(beanManager, YourBean.class);
// ...

或者,如果您已经在使用 OmniFaces 1.x,或者愿意使用它,请使用其 Beans 实用程序 class(仅自 1.6 起可用):

YourBean yourBean = Beans.getReference(YourBean.class);
// ...

两者都是 return 代理引用,您可以安全地将其分配为 SystemEventListener class 在构造期间的实例变量。