【问题标题】:Spring DAO is not injected in JSF managed beanSpring DAO 未注入 JSF 托管 bean
【发布时间】:2013-01-23 20:26:07
【问题描述】:

我在我的演示应用程序中使用 JSF2+Spring3.1+Hibernate4,我想使用注释来创建会话工厂,但是我的 DAO 类没有在 Jsf Managed Bea 类中初始化,所以我得到空指针异常。 我的 applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                http://www.springframework.org/schema/tx 
                http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                http://www.springframework.org/schema/context 
                http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:annotation-config></context:annotation-config>

    <context:component-scan base-package="com.otv"></context:component-scan>


    <!-- Data Source Declaration -->
    <bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"  >
        <property name="driverClass" value="org.postgresql.Driver" />   
        <property name="jdbcUrl" value="jdbc:postgresql://localhost:5432/postgres" />   
        <property name="user" value="postgres" />   
        <property name="password" value="hariom" /> 
        <property name="maxPoolSize" value="10" />
        <property name="maxStatements" value="0" />
        <property name="minPoolSize" value="5" /> 
    </bean>

    <!-- Session Factory Declaration -->
    <bean id="SessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean ">
        <property name="dataSource" ref="DataSource" />
        <property name="annotatedClasses">
            <list>
                <value>com.otv.model.User</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
          <property name="packagesToScan" value="com.otv.user"></property>
    </bean>


    <!-- Transaction Manager is defined -->
    <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager" >
       <property name="sessionFactory" ref="SessionFactory"/>
    </bean>


  <!-- Enable the configuration of transactional behavior based on annotations -->
    <tx:annotation-driven transaction-manager="txManager"/>

</beans>

UserDAO.java 类

package com.otv.user.dao;

import java.util.List;

import com.otv.model.User;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

/**
 * 
 * User DAO
 * 
 * @author onlinetechvision.com
 * @since 25 Mar 2012
 * @version 1.0.0
 *
 */

@Repository
@Transactional
public class UserDAO   {

    @Autowired
    private SessionFactory sessionFactory;

    /**
     * Get Hibernate Session Factory
     * 
     * @return SessionFactory - Hibernate Session Factory
     */
/*  public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    *//**
     * Set Hibernate Session Factory
     * 
     * @param SessionFactory - Hibernate Session Factory
     *//*
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }*/



    /**
     * Add User
     * 
     * @param  User user
     */
    public void addUser(User user) {
        sessionFactory.getCurrentSession().save(user);
    }

    /**
     * Delete User
     * 
     * @param  User user
     */
    public void deleteUser(User user) {
        sessionFactory.getCurrentSession().delete(user);
    }

    /**
     * Update User
     * 
     * @param  User user
     */
    public void updateUser(User user) {
        sessionFactory.getCurrentSession().update(user);
    }

    /**
     * Get User
     * 
     * @param  int User Id
     * @return User 
     */
    public User getUserById(int id) {
        List list = sessionFactory.getCurrentSession()
                                            .createQuery("from User where id=?")
                                            .setParameter(0, id).list();
        return (User)list.get(0);
    }

    /**
     * Get User List
     * 
     * @return List - User list
     */
    public List<User> getUsers() {
        List list = sessionFactory.getCurrentSession().createQuery("from User").list();
        return list;
    }

}

还有我的 managedBean 类

package com.otv.managed.bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;

import com.otv.model.User;
import com.otv.user.dao.UserDAO;
import com.otv.user.service.IUserService;

/**
 * 
 * User Managed Bean
 * 
 * @author onlinetechvision.com
 * @since 25 Mar 2012
 * @version 1.0.0
 *
 */
@ManagedBean(name="userMB")
@RequestScoped
public class UserManagedBean implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final String SUCCESS = "success";
    private static final String ERROR   = "error";

    //Spring User Service is injected...


    List<User> userList;

    private int id;
    private String name;
    private String surname;

      @Autowired
      private UserDAO userDAO;
    /**
     * Add User
     * 
     * @return String - Response Message
     */
    public String addUser() {
        try {
            User user = new User();
            user.setId(getId());
            user.setName(getName());
            user.setSurname(getSurname());
            userDAO.addUser(user);
            return SUCCESS;
        } catch (DataAccessException e) {
            e.printStackTrace();
        }   

        return ERROR;
    }

    /**
     * Reset Fields
     * 
     */
    public void reset() {
        this.setId(0);
        this.setName("");
        this.setSurname("");
    }

    /**
     * Get User List
     * 
     * @return List - User List
     */
    public List<User> getUserList() {
        userList = new ArrayList<User>();
        userList.addAll(userDAO.getUsers());
        return userList;
    }

    /**
     * Get User Service
     * 
     * @return IUserService - User Service
     */

    /**
     * Set User List
     * 
     * @param List - User List
     */
    public void setUserList(List<User> userList) {
        this.userList = userList;
    }

    /**
     * Get User Id
     * 
     * @return int - User Id
     */
    public int getId() {
        return id;
    }

    /**
     * Set User Id
     * 
     * @param int - User Id
     */
    public void setId(int id) {
        this.id = id;
    }

    /**
     * Get User Name
     * 
     * @return String - User Name
     */
    public String getName() {
        return name;
    }

    /**
     * Set User Name
     * 
     * @param String - User Name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Get User Surname
     * 
     * @return String - User Surname
     */
    public String getSurname() {
        return surname;
    }

    /**
     * Set User Surname
     * 
     * @param String - User Surname
     */
    public void setSurname(String surname) {
        this.surname = surname;
    }

}

现在在 Managedbean 方法中,DAO 对象为空,我得到空指针异常

警告:#{userMB.addUser}:java.lang.NullPointerException javax.faces.FacesException:#{userMB.addUser}: java.lang.NullPointerException 在 com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:118) 在 javax.faces.component.UICommand.broadcast(UICommand.java:315) 在 javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794) 在 javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259) 在 com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81) 在 com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) 在 com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) 在 javax.faces.webapp.FacesServlet.service(FacesServlet.java:593) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) 在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) 在 org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) 在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168) 在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) 在 org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927) 在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) 在 org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1001) 在 org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585) 在 org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) 在 java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 在 java.lang.Thread.run(Thread.java:662) 引起: javax.faces.el.E​​valuationException:java.lang.NullPointerException 在 javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102) 在 com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102) ... 23 更多原因:java.lang.NullPointerException at com.otv.managed.bean.UserManagedBean.addUser(UserManagedBean.java:57) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 在 java.lang.reflect.Method.invoke(Method.java:597) 在 org.apache.el.parser.AstValue.invoke(AstValue.java:264) 在 org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:278) 在 com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105) 在 javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88) ... 24 更多

【问题讨论】:

  • 你不能使用Autowired将spring bean注入JSF。你必须在UserDAO上使用@ManagedProperty而不是Autowired。你必须删除faces-coifig.xml中的任何条目避免XML 配置抑制注释。您可以查看此春季网站以获取其他配置。static.springsource.org/spring/docs/2.5.x/api/org/…
  • 不幸的是,您也不能使用@ManagedProperty 将 Spring bean 注入 JSF 托管 bean。这样的注入可能有效,但仅适用于@SessionScoped@RequestScoped bean,因为这些注释将分别转换为@Scope("session")@Scope("request"),强制bean 由Spring 和living 管理在其上下文中,但由于在 faces-config.xml EL 解析器中声明,它们将在 JSF 视图中完全可见。不要自欺欺人,让 Spring 框架来管理你的 bean。
  • 那么最好的解决方案是什么?
  • 当 UserManagedBean 具有非瞬态字段 UserDAO 时,它如何可序列化?

标签: spring hibernate jsf-2


【解决方案1】:

简而言之,您的 bean 应该完全由 JSF 或 Spring 管理。

这一点有很多证据。只需在此处和/或网络上查找“JSF + spring integartion”即可。

现在让我考虑一下这个问题,以加深您的理解。

许多 Web 应用程序由多个“层”组成,也称为应用程序的“层”:用于查看应用程序页面的 Web 层或表示层、用于执行应用程序逻辑和业务规则的业务层或中间层和数据层,或持久层,用于向/从数据库传输数据。这些层可能具有以下配置:

  1. Entity 类将保存从您的数据库派生的数据,并且最可能被 Hibernate 等 ORM 框架使用;
  2. DAO 类将用于访问数据库并至少对数据库执行 CRUD 操作,最重要的是为您的 Web 部件返回 Web 层的实体类;
  3. Service 将反映您的应用程序提供的业务操作的类;
  4. Bean 类将备份您的视图,并且很可能包含您网页中使用的数据、操作方法、转换等。

下一步是为您的 Web 应用程序选择框架。

  1. 您为所有层选择 Spring,这意味着您的 DAO 将是 @Repository 类,您的服务将是 @Service 类,您的 Bean 将是 @Component 类。您很可能会使用像 Hibernate 这样的 ORM 框架来处理数据库,因此您的实体将是 JPA @Entity 以 Hibernate 样式正确配置的类。您的视图技术很可能是为与 Spring 核心一起工作而精心设计的 Spring MVC。比如Mkyong有很多简单的Spring使用教程。

  2. 您为所有层选择原生 JSF+EJB 框架,这意味着您的 DAO 和服务将是 @EJB 类,您的 bean 将是 @ManagedBean 类。您很可能还会使用 Hibernate 作为 ORM 解决方案和 JPA 提供者,并将通过 EntityManager 进行数据库访问。您的视图技术将是 JSF,因为它很自然地打算与上述技术一起使用。例如,BalusC 有很多关于使用 JSF 的启发性教程。

这两种选择都有其拥护者和反对者。有人说为什么要选择不是 Sun 的 Oracle 解决方案的原生解决方案,其他人则说它太复杂和令人困惑,而且缺乏可供学习的资源。

由于这不是技术选择上的争议,我不会在这里详细介绍,但会指出 Spring 是一个轻量级容器,它将在 Tomcat 等简单的 servlet 容器上运行,而 EJB 需要像 Glassfish 这样的应用程序服务器才能运行.我认为这是将 JSF 作为基于组件的 Web 框架和 Spring 作为轻量级依赖注入和业务层框架相结合的主要驱动力。

当我们决定将这两个框架集成在一起时,我将解释集成的工作原理以及 NPE 发生的原因。

  1. 实体类要么是 JPA/Hibernate 注释类,要么是由 xml 配置的简单 POJO。
  2. DAO 将@Repository 实现基本接口以避免紧密耦合。它们将由 Spring 框架管理。
  3. 服务将是@Service,也实现基本接口。它们也将由 Spring 框架管理。请注意,如果您使用@Transactional 标记服务方法,Spring 框架将为您提供开箱即用的事务管理。
  4. 因此,Beans 必须是@Component@Scope("value"),并且如果您想将其用作依赖注入框架,则必须由Spring 管理,从而允许通过@Autowired 访问您的服务和其他bean。

因此,NPE 源于误解,即作为视图的逻辑部分的 bean 应该由 JSF 管理(请注意,@ManagedProperty 也不能正常工作)。 bean 由 JSF 实例化,但您的服务驻留在 JSF 知道的 Spring 上下文中,因此无法进行注入。另一方面,如果 bean 保留在 Spring 上下文中,它的生命周期和依赖项将由 Spring 注入。

因此,要使其正常工作,请将 bean 标记为

@Component
@Scope("request")
public class SpringManagedBeanToBeUsedByJSF {

    ...

    @Autowired
    private SpringService springService;

    ...

}

并满足将 Spring 与 JSF 结合使用的所有先决条件。如果您迷失方向,请咨询this excellent example 进行设置。这样,所有 bean 都将由 Spring 管理,并且当您在 faces-config.xml 中附加 EL-resolver(允许 JSF '看到' Spring beans)和 web.xml 中的必要侦听器时,它们将在 JSF 视图中可见。当您这样做时,所有 Spring bean 都可以在 .xhtml 文件中引用,如果您需要将 JSF 操作放在 bean 中,只需将它们放在(Spring)托管 bean 中或使它们实现至关重要到JSF接口等。只有这样才能实现集成。当然,你也可以在应用程序中使用 JSF 托管的 bean,@FacesConverter@FacesValidator 类,只是不要互相干扰,但是在一个应用程序中使用两个依赖注入框架至少会造成混乱。

希望这有助于您更好地了解情况。

您的代码也存在一些问题,我不会在这个一般性答案中强调。

【讨论】:

  • 非常详尽的答案。使用 Spring 而不是 JSF 来管理视图的最重要的缺点是缺少 @ViewScoped。作为替代方法,我使用来自@ApplicationScoped 托管bean 的servlet 上下文访问Web 应用程序上下文。然后我将 Spring 上下文添加到我的应用程序 bean 中,所以我只需要将这个 bean 注入到我的 @ViewScoped 中。这是一个中间步骤,但至少它有效。
【解决方案2】:

你能不能试试 UserDAO 的 ManagedProperty 注释

@ManagedProperty("#{userDAO}")
private UserDAO userDAO;

private void setUserDAO(UserDAO userDAO){
this.userDAO=userDAO;
}

您可能还需要更改 dao 注释

@Repository("userDAO")
@Transactional
public class UserDAO

【讨论】:

  • 所以我必须删除自动装配?
【解决方案3】:

从您的 applicationContext.xml 中删除 bean 声明。当您使用 @Repository 注释 UserDao 时,spring 容器将使用它创建一个单例 bean。这应该可以解决您的问题。

从 applicationContext.xml 中删除它:<bean id="UserDAO" class="com.otv.user.dao.UserDAO"> </bean>

【讨论】:

  • 抱歉,我在得到空指针异常后添加了 bean 声明,我再次更改了代码,但仍然是同样的问题
  • 好的,如果您通过删除它来获得 NPE,这意味着您的组件扫描无法正常工作。你确定你的 UserManagedBean 在 spring 上下文中被初始化并被注入到客户端类中。
  • UserManagedBean 是从 JSG 页面调用的,当我提交表单时,在 userDAO.addUser(user); 之后调用的 ManagedBean 方法和方法进程;通过异常因为 UserDAO 对象为空,为什么我不知道
  • 您正在获得 NPE,因为您的 UserManagedBean 未在 spring 上下文中初始化。是否有任何弹簧组件处理您的请求?还要检查您是否在 web.xml、 org.springframework.web.context.ContextLoaderListener org 中添加了以下内容。 springframework.web.context.request.RequestContextListener
  • 这些条目在 web.xml 文件中,在 faces.config.xml 中包含 org.springframework.web。 jsf.el.SpringBeanFacesELResolver
猜你喜欢
  • 1970-01-01
  • 2014-07-01
  • 2012-01-27
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 2015-03-11
  • 2013-07-28
  • 2013-05-08
相关资源
最近更新 更多