【问题标题】:JSF ManagedBean - injected properties not working correctly on STATE_SAVING_METHOD=clientJSF ManagedBean - 注入的属性在 STATE_SAVING_METHOD=client 上无法正常工作
【发布时间】:2012-04-16 16:33:33
【问题描述】:

这两天我遇到了一个问题,我无法摆脱它。

我遇到的问题是在反序列化后使用 MangedBean 属性(我猜)。
属性 (purchaseManager) 使用 Spring 设置,并使用扩展 MyBatis 作为数据映射器的 DAO 与 DB 进行交互。
事实上,在第一次访问页面时,init() 方法中的 purchaseManager.getAll() 工作正常。
当我尝试从按钮调用 refreshList() 作为操作时,DAO 内的 getSqlSession() 上有 NullPointerException。

只放相关代码情况如下:

@ManagedBean(name = "purchaseController")
@ViewScoped
public class PurchaseController implements Serializable{

    @ManagedProperty(value = "#{purchaseManager}")
    private PurchaseManager purchaseManager;

    @PostConstruct
    public void init(){
        purchaseManager.getAll();
    }

    public void refreshList(){
        purchaseManager.getAll();
    }
}

public class PurchaseManagerImpl implements PurchaseManager, Serializable {
    PurchaseDAO purchaseDAO;

    public void getAll() {
        purchaseDAO.getAll()
    }
}

public class PurchaseDAOImpl extends SqlSessionDaoSupport implements PurchaseDAO, Serializable {

    public void getAll() {
        SqlSession session = getSqlSession();  // when the call comes from refreshList(), session is null
        session.selectList("PAYMENT.getAll", null);
    }
}

in web.xml
<context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>server</param-value>
</context-param>

如果我将 STATE_SAVING_METHOD 更改为服务器应用程序可以正常工作,但这不是我想要的。如果我将 ManageBean 作为 RequestScope 也是一样,但这也会影响我的要求。

提前感谢任何人的帮助! 埃尔玛

【问题讨论】:

  • 我不使用 Spring,所以我可能完全错了,但是您为什么尝试将 Spring 托管 bean 作为 JSF 托管属性注入?我从来没有见过这个。 Spring对此有自己的注释。
  • 在 Spring 基础设施中,我有逻辑(DAO 和服务),这是一个自己的项目 BL,由其他两个 Web 应用程序(前端和管理工具)使用。许多参考资料显示了这种将 ManagedBeans 作为其他托管 bean 的属性注入的方式。这里是一个例子:mkyong.com/jsf2/injecting-managed-beans-in-jsf-2-0
  • 是的,我知道注入 JSF 托管 bean 的工作原理,但是您将 Spring 托管 bean 视为 JSF 托管 bean。如果它是一个 EJB(Spring 应该取代它),那么您将使用 @EJB 而不是 @ManagedProperty,它基本上会注入一个完全可序列化的代理实例。 Spring真的没有一些注释吗? @Autowired 左右?
  • @Autowired 似乎是正确注入弹簧豆的解决方案。虽然,我有错误 com.sun.faces.mgbean.ManagedBeanCreationException: An error occurred on managed bean purchaseController 在 PurchaseController.init() 方法中执行资源注入。我的应用程序只有在使用@ManagedProperty 时才显得稳定。根据您的经验,只有@ManagedProperty 的 PRD 环境最终会出现什么问题?
  • 感谢@BalusC 的评论。从您的观察开始,我解决了在 Spring bean 定义中添加 &lt;aop:scoped-proxy proxy-target-class="false" /&gt; 的问题。现在我的经理/服务对象已按我所说的那样定义,一切正常。所以我的数据库(MyBatis)引用不再为空。

标签: spring jsf viewstate mybatis managed-bean


【解决方案1】:

解决了在通过 Spring 声明的服务/管理器的定义中添加 &lt;aop:scoped-proxy proxy-target-class="false" /&gt; 的错误。这使得注入完全可序列化的代理实例成为可能。

<bean id="purchaseManager" class="al.ozone.bl.manager.impl.PurchaseManagerImpl">    
    <property name="purchaseDAO" ref="purchaseDAO" />   
    <aop:scoped-proxy proxy-target-class="false" />
</bean> 

proxy-target-class="false" 用于告诉PurchaseManagerImpl 已经实现了一个接口。如果设置为true 或省略,则必须使用CGLIB2 库。

通过这种方式,JSF 使用 Spring+MyBatis 从 DB 中正确获取数据。

关于这一点(更理论上)的谜团(对我来说)是:

  • MyBatis 对象 (PurchaseDAOImpl) 和 dataSource 是否在幕后正确处理?
  • 是否在每个 HTTP 请求上重新创建或恢复它们?

请记住,我有 STATE_SAVING_METHOD=client 和 BackingBean 作为 ViewScope
我的目标是让服务器变得更轻,因为我期望用户交互的数量很高。

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <property name="poolPreparedStatements" value="true" />
    <property name="defaultAutoCommit" value="false" />
</bean>

非常感谢任何人为此事提供一些启示!

参考链接:

Spring session-scoped beans (controllers) and references to services, in terms of serialization

http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-scopes-other-injection

http://www.infoq.com/presentations/Whats-New-in-Spring-3.0

【讨论】:

  • 解决了这个错误。将此问题设置为已接受,也许可以帮助其他有相同问题的人。
猜你喜欢
  • 1970-01-01
  • 2011-06-12
  • 1970-01-01
  • 1970-01-01
  • 2016-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多