gpt4 book ai didi

java - JSF 中的 CDI 全局事件处理 (javax.enterprise.event)

转载 作者:行者123 更新时间:2023-11-29 05:54:33 24 4
gpt4 key购买 nike

我想根据 javax.enterprise.event.Event 实现事件处理程序界面。目前它运行良好,但仅限于单个 session 。我的环境是 JBoss-7.1.1.FinalJSF2。我可以在这个简化的(有效的)示例中演示该问题:

@Named 里面Bean 我定义了一个 Event<MyEjb>并且可以触发事件。

@Inject private Event<MyEJB> ejbChanged;

public void test()
{
ejbChanged.fire(new MyEjb());
}

这在 @Named @SessionScoped 中被识别Bean 和我可以轻松处理这个

public void
onChanged(@Observes(notifyObserver = Reception.IF_EXISTS) final MyEjb ejb)
{
logger.info("onChanged "+ejb.toString());
}

但不幸的是 onChanged仅在 @SessionScoped 中调用属于当前用户 session 的 Bean。但我也想访问属于其他用户 session 的 Beans。这个 CDI 事件处理可能吗?

最佳答案

Markus Dahm 在他的博客条目 here 中描述的解决方案

他向 Web 应用程序的所有 Activity session 发送事件的解决方案涉及扩展现有的 CDI 观察者模式以支持全局事件。

相关代码如下:

首先我们需要一个 GlobalevHttpSessionController 来注册和处理所有 HTTP session 并将所有事件委托(delegate)给 session :

@ApplicationScoped
public class GlobalevHttpSessionController {
public static final String
EVENT_ATTRIBUTE_NAME = "HttpSessionControllerEvent";

private final List _httpSessions = new ArrayList();

public List getHttpSessions() {
return new ArrayList(_httpSessions);
}

public void addSession(final HttpSession httpSession) {
_httpSessions.add(httpSession);
}

public void removeSession(final HttpSession httpSession) {
_httpSessions.remove(httpSession);
}

public void fireEvent(final GlobalEvent eventObject) {
for (final HttpSession session : _httpSessions) {
fireEvent(session, eventObject);
}
}

private void fireEvent(final HttpSession session, final GlobalEvent eventObject) {
try {
final List globalEvents = getGlobalEvents(session);

globalEvents.add(eventObject);
} catch (final Exception e) {
throw new IllegalStateException("fireEvent", e);
}
}

private synchronized List getGlobalEvents(final HttpSession session) {
List globalEvents = (List) session.getAttribute(EVENT_ATTRIBUTE_NAME);

if (globalEvents == null) {
globalEvents = new ArrayList();
session.setAttribute(EVENT_ATTRIBUTE_NAME, globalEvents);
}

return globalEvents;
}
}

其中 GlobalEvent 只是所有全局事件的一个简单的可序列化父类(super class):

public abstract class GlobalEvent implements Serializable {
private static final long serialVersionUID = 1L;
}

接下来,我们需要一个 HTTP 监听器来添加和删除 Activity 的客户端 session :

@WebListener
public class GlobalevHttpSessionListener implements HttpSessionListener {
@Inject
private GlobalevHttpSessionController _httpSessionController;

public void sessionCreated(final HttpSessionEvent se) {
_httpSessionController.addSession(se.getSession());
}

public void sessionDestroyed(final HttpSessionEvent se) {
_httpSessionController.removeSession(se.getSession());
}
}

为了将事件分派(dispatch)给客户端,他选择使用 JSF PhaseListener 查找传入事件。其他解决方案,例如使用过滤器,也是可能的。监听器查找全局事件并使用 CDI bean 管理器将它们分派(dispatch)到本地 session 。管理器实例是通过 JNDI 查找获得的(根据规范,bean 管理器必须由 java:comp/BeanManager 下的容器绑定(bind))。不幸的是,我们不能在这里使用 CDI 注入(inject),因为阶段监听器不是由 CDI 实例化的,而是由 Java Server Faces (JSF) 框架实例化的。然而,该框架确实提供了我们通过 FacesContext 对象访问 HTTP session 所需的所有信息

public class GlobalevEventPhaseListener implements PhaseListener {
public void beforePhase(final PhaseEvent event) {
final FacesContext facesContext = event.getFacesContext();
final HttpSession httpSession =
JSFUtil.getHttpSession(facesContext);

if (httpSession != null) {
final List globalEvents = getGlobalEvents(httpSession);

if (!globalEvents.isEmpty()) {
fireEvents(globalEvents);
}
}
}

private void fireEvents(final List globalEvents) {
final BeanManager beanManager = lookBeanManager();

if (beanManager != null) {
try {
for (final GlobalEvent devaGlobalEvent : globalEvents) {
beanManager.fireEvent(devaGlobalEvent);
}
} catch (final Exception e) {
throw new IllegalStateException("fireEvents", e);
}
}
}

@Override
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE; // RESTORE_VIEW;
}

private BeanManager lookBeanManager() {
try {
final Object obj =
new InitialContext().lookup("java:comp/BeanManager");

return (BeanManager) obj;
} catch (final Exception e) {
throw new
IllegalStateException("Lookup bean manager", e);
}

return null;
}

private synchronized List getGlobalEvents(final HttpSession httpSession) {
final List events = (List) httpSession.getAttribute(
GlobalevHttpSessionController.EVENT_ATTRIBUTE_NAME);
final List result = new ArrayList();

if (events != null) {
result.addAll(events);
events.clear();
}

return result;
}
}

最后,我们需要在 faces-config.xml 中注册我们的监听器:

<lifecycle>
<phase-listener>
de.akquinet.jbosscc.globalev.listener.GlobalevEventPhaseListener
</phase-listener>
</lifecycle>

代码也可在 github 上获得

感谢马库斯!

关于java - JSF 中的 CDI 全局事件处理 (javax.enterprise.event),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12675186/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com