随着CDI的portlet集成库的放出,我们可以在JSF portlet中通过Portlet桥,利用CDI带来的巨大优点。
怎么使用?
除了通常的Portlet桥依赖以外,在portlet中使用CDI还需要:
- 在项目中添加以下依赖包:
<dependency>
<groupId>org.gatein</groupId>
<artifactId>cdi-portlet-integration</artifactId>
<version>1.0.2.Final</version>
</dependency>
- 在WAR包的WEB-INF目录下,新增一个空的beans.xml文件。
- 在portlet.xml中,添加以下过滤器的定义:
<filter>
<filter-name>PortletCDIFilter</filter-name>
<filter-class>org.gatein.cdi.PortletCDIFilter</filter-class>
<lifecycle>ACTION_PHASE</lifecycle>
<lifecycle>EVENT_PHASE</lifecycle>
<lifecycle>RENDER_PHASE</lifecycle>
<lifecycle>RESOURCE_PHASE</lifecycle>
</filter>
<filter-mapping>
<filter-name>PortletCDIFilter</filter-name>
<portlet-name>yourPortletName</portlet-name>
</filter-mapping>
PortletCIDFilter只包括接收到的portlet请求可以使用CDI。如果你的程序代码框架需要处理portlet响应,则需要使用即可以处理请求又能够处理响应的PortletCDIResponseFilter来代替。
@RequestScoped
使用此作用域的bean在portlet中的行为与常规的JSF不同。在portelt中,设定为ActionRequest的bean类,其中任何修改的内容都无法到达portlet生命周期的其他阶段,包括RenderRequest。所以,建议不要一个JSF的portlet中的CDI bean类中,使用此作用域。推荐使用GateIn 3.6.0 Final中新增的@PortletLifecycleScoped。这个新的作用域允许为了渲染portlet,在一个action里面,设置你想要的数据;并且可以从ActionRequest到RenderRequest阶段保持Bean的实体。
@ConversationScoped
临时会话跟一个标记为@RequestScoped的Bean类具有相同的行为。因此,不推荐为渲染JSF portlet而让数据可用。
预计JSF portlet会提供对长会话的支持,但是,仍然有一些问题需要注意:
- 在RenderRequest阶段,结束一个长会话时,将导致接下来的portlet渲染出现一个ConversationNotFoundException。这是因为portlet渲染所触发的url,包含有cid参数;CDI据此参数确定是创建一个长会话还是一个临时会话。如果会话终结时参数仍存在,那么在下次portlet渲染时,将会试图重新启动结束该会话。
- 使用AJAX来开始或者结束一个长会话是不错的选择。我们需要重新渲染包括URL在内的所有portlet组件,从而让CDI知道我们点击一个链接或者按钮所使用的会话。如果不更新URL,链接有可能被赋予一个旧的cid值,从而导致ConversationNotFoundException,或者直接就没有cid,导致所有的调用都是临时会话。
GateIn Scopes
最近,在GateIn 3.6.0 Final版本中提供了两个新的作用域:@PortletLifecycleScoped与@PortletRedisplayScoped。这两个作用域在JSF portlet中非常实用,并且可以跟其他的CDI作用域的bean类进行无缝交互。这些作用域将在GateIn的博客文章中展开讨论。
希望这篇文章能够指出在JSF portlet开发中,使用CDI时的一些常见陷阱。