Inject CDI managed bean in SystemEventListener

时间:2015-05-24 20:30:55

标签: jsf cdi managed-bean systemeventlistener

I have used answer of How to disable elements from within a ViewHandler after jsf has embedded the composite component? to programmatically disable all components in all forms. A SystemEventListener catches and disables all components.

What I would like to add is getting some logic from a CDI bean. It appears that I cannot @Inject a CDI bean inside SystemEventListener. Is there some other mechanism to get logic from CDI beans? I have lots of components and it would be very time consuming to add disabled="#{bean.disabled}" to all components. As I understand this is the right approach to "batch disable" or I'm heavily mistaken here?

1 个答案:

答案 0 :(得分:1)

似乎你还没有使用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实用程序类(仅限1.6以后可用):

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

两者都返回一个代理引用,您可以在构造期间将其安全地指定为SystemEventListener类的实例变量。