我们正在使用 JSF 2、Spring 和 Hibernate 构建一个应用程序。MyFaces Orchestra 用于提供我们在应用程序中的大多数页面使用的会话范围(以利用 Orchestra 对 Hibernate 会话的管理)。我们所有的 bean 都被声明为使用 conversation.access 范围,这(根据 Orchestra 文档)应该意味着一旦用户导航到不包含对该支持 bean 实例的任何引用的页面,bean 就会从范围中删除.
我遇到的问题是,如果我从一个视图导航一条路而没有明确地使对话无效,如果他们稍后回到该视图,它仍然具有与以前相同的数据。我在所有支持 bean 中实现了 ConversationBindingListener 方法,我可以看到它们何时从对话中删除,并且我可以看到它们在很多情况下都不是。
使问题更令人困惑的是,当我导航到某些页面(视图)而不是其他页面时,支持 bean 被删除。我想这可能是因为页面无意中引用了 EL 中的其他支持 bean,但我找不到任何内容。我还认为,这个问题可能只发生在我从一个具有 conversation.access 范围 bean 的页面导航到使用不同的 conversation.scoped bean 的另一个页面时。但是,在从会话中删除它的情况下,该页面还包含对 conversation.access 范围 bean 的引用。
正如我之前所说,使用 Conversation.getCurrentInstance().invalidate() 显式地使对话无效是有效的。但是,不可能对每个用例都显式地使对话无效,因为这将是一个非常常见的用例,因为用户只需单击其中一个导航链接即可离开视图。
附加细节:我们使用的是 Hibernate 3.6(而不是 JPA),这意味着我们必须使用HibernatePersistenceContextFactory。
- MyFaces Orchestra (myfaces-orchestra-core20-1.4.jar)
- JSF 2 (Mojarra 2.0.4)
- 春天 3.0
- PrimeFaces 2.2.1
- RichFaces 4.0.0
这是我的 Spring 上下文配置的样子(对于 Orchestra)。
<!-- 1. initialization of all orchestra modules (required for core15 module) -->
<import resource="classpath*:/META-INF/spring-orchestra-init.xml" />
<!-- 2. the conversation scopes -->
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="conversation.manual">
<bean
class="org.apache.myfaces.orchestra.conversation.spring.SpringConversationScope">
<property name="timeout" value="30" />
<property name="advices">
<list>
<ref bean="persistentContextConversationInterceptor" />
</list>
</property>
</bean>
</entry>
<entry key="conversation.access">
<bean
class="org.apache.myfaces.orchestra.conversation.spring.SpringConversationScope">
<property name="timeout" value="30" />
<property name="advices">
<list>
<ref bean="persistentContextConversationInterceptor" />
</list>
</property>
<property name="lifetime" value="access" />
</bean>
</entry>
</map>
</property>
</bean>
<!-- 3. the "entity manager" manager -->
<bean id="persistentContextConversationInterceptor"
class="org.apache.myfaces.orchestra.conversation.spring.PersistenceContextConversationInterceptor">
<property name="persistenceContextFactory" ref="persistentContextFactory" />
</bean>
<!-- 4. conversation - persistence adapter -->
<bean id="persistentContextFactory"
class="com.acme.infra.orchestra.hibernate.HibernatePersistenceContextFactory">
<property name="entityManagerFactory" ref="sessionFactory" />
</bean>
<!-- 5. persistence -->
<bean id="managedDataSource"
class="org.apache.myfaces.orchestra.connectionManager.ConnectionManagerDataSource">
<property name="dataSource" ref="dataSource" />
</bean>
下面是几个 JSF 支持 bean 声明的示例。
<bean id="quoteSummaryBackingBean" class="com.acme.ui.backing.QuoteSummaryBackingBean"
scope="conversation.access" orchestra:conversationName="QuoteSummaryConversation">
<property name="quotingBusinessService" ref="quotingBusinessService"/>
<property name="customerBusinessService" ref="customerBusinessService"/>
<property name="referenceDataBusinessService" ref="referenceDataBusinessService"/>
<property name="quoteExportBusinessService" ref="quoteExportBusinessService" />
</bean>
<bean id="createQuoteBackingBean" class="com.acme.ui.backing.CreateQuoteBackingBean"
scope="conversation.access" orchestra:conversationName="CreateQuoteConversation">
<property name="quotingBusinessService" ref="quotingBusinessService"/>
<property name="customerBusinessService" ref="customerBusinessService"/>
<property name="referenceDataBusinessService" ref="referenceDataBusinessService"/>