【问题标题】:Why is my Spring @Autowired field returns null?为什么我的 Spring @Autowired 字段返回 null?
【发布时间】:2016-10-28 13:35:37
【问题描述】:

这不是this 问题的重复。所以请不要因为“重复”的原因而关闭它..


我正在尝试将 bean 自动装配到 java 类中。我的问题是 playerDAO 仍然为空并且没有被初始化。

mvc-dispatcher-service.xml

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

    <context:component-scan base-package="ngdemo"/>

    <mvc:annotation-driven/>

    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="mySessionFactory"/>
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>    
</beans>

PlayerDAO.java

@Repository
@SuppressWarnings({"unchecked", "rawtypes"})
public class PlayerDAO {
    @Autowired
    private SessionFactory sessionFactory;

    @Transactional
    public Player getPlayerByUsername(String username) {
      //some code
    }
}

LoginRestService.java

@Path("/v1")
@Controller
public class LoginRestService {

    @Autowired
    private PlayerDAO playerDAO;

    @Path("/login")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public Response authenticateUser(@FormParam("username") String username,
                                     @FormParam("password") String password, @Context UriInfo request) {
     playerDAO.getPlayerByUsername(username);
     //NPE, playerDAO here is null when I'm trying to access it
    }    
}

我错过了什么?

此处提供完整代码:https://github.com/Ferenus/hestalis

【问题讨论】:

标签: java spring spring-mvc


【解决方案1】:

您确定您的控制器包名称是“ngdemo”而不是“com.pack.ngdemo”吗?您是否使用数据库?可能是您从查询中获得空值,您能否告诉我您在 getplayerbyusername() 方法中使用的查询。

试试这个

public TypedQuery<User> findUsersByNameEquals(String name) {
    if (name == null || name.length() == 0) { 
        throw new IllegalArgumentException("The name argument is required"); 
    }

    TypedQuery<User> q = entityManager.createQuery("SELECT o FROM User AS o WHERE o.username = :name", User.class);
    q.setParameter("name", name);

    return q;
}

public boolean loginWithUserPass(String username, String password){

    TypedQuery<User> q = entityManager.createQuery("SELECT o FROM User AS o WHERE o.username = :name and o.password = :pass", User.class);
    q.setParameter("name", username);
    q.setParameter("pass", password);

    List<User> results = q.getResultList();
    if (!results.isEmpty()) return true;

    else return false;
}

不要尝试完全相同的代码,因为我使用过实体管理器。尝试类似的东西。这可能会有所帮助。

【讨论】:

  • PlayerDAO 在package ngdemo.dao;。我正在使用数据库。 playerDAO 肯定是 null,而不是来自 getPlayerByUsername 的查询。
  • 如果你不会在播放器 DAO 中插入任何值,它将自动为 null。例如,如果您想在您的网络应用程序中使用登录功能,您需要选择用户名 eq 输入用户名和密码 eq 输入密码的行,或者只计算用户名和密码 eq 输入用户名和密码的行。
  • 并打印表单参数以确保它们的值正确
  • 我已经编辑了这个问题,让你看看 NPE 是在哪里产生的。我应该以某种不同的方式初始化productDAO,所以它不会为空吗?
  • 不,你的函数应该自动初始化 playerDao
【解决方案2】:

我应该建议你使用接口而不是实现,在你的控制器中你正在注入 DAO 实现,而你应该注入服务接口。

如果你不想使用服务类,我建议你注入一个接口:

public class PlayerDAO implements IPlayerDAO

并在您的控制器注入接口中。

public class LoginRestService {

    @Autowired
    private IPlayerDAO IPlayer;

这是一个很好的做法。

另一方面,你在 DAOS 中设置事务,这不是一个好主意,你应该在服务类中指定它。

最后说说你的问题,一个spring组件中的null,一般是因为没有正确指定组件扫描。

问候。

【讨论】:

  • 感谢您的良好实践学习。但是如何正确指定组件扫描呢?
  • 嗨,你能把你的课程放在哪里吗?然后复制 中的确切路径。我应该推荐,首先在控制器和 dao 之间添加接口和服务层。并将事务性转移到服务层。最后一步应该是注入接口。
  • package ngdemo.dao; PlayerDAO.java。而LoginRestService.java:package ngdemo.rest;那么应该是准确的路径吧?我可以使用两次吗?
  • 添加这个包进行扫描:,
  • ` ` 没有帮助,playerDAO 还在空值。我会尝试使用界面。
【解决方案3】:

我尝试了你的应用程序的 github 版本,添加了一个测试,它运行良好:https://github.com/michalmela/hestalis

检查您的测试配置。另外,请不要无缘无故地按照其他回复的建议为服务添加接口。

【讨论】:

  • 也许它对你有用,因为你使用:@ContextConfiguration(locations = "classpath:**/mvc-dispatcher-servlet.xml")。我尝试在我的 LoginRestService 类中使用 ContextConfiguration,但它没有帮助,因为它无法解析 webapp.WEB-INF 中 mvc-dispatcher-servlet.xml 的路径。也许我应该把它放在不同的包装里?我的项目是否有可能看不到这个 xml 文件?如何让我的应用看到它?
  • 不,@ContextConfiguration 仅用于测试,请勿在生产课程中使用。无论如何,我想它归结为web.xml。告诉我你正在使用什么 servlet 容器(tomcat、jetty 等等?),我会看看。
  • tomcat。你可能是对的,因为我没有在 web.xml 中执行任何 spring 配置。我认为没有它也能正常工作。
【解决方案4】:

尝试在 PlayerDAO 类的顶部添加 @Component 注释。可能是这样你的 bean 会被 Spring 正确扫描。这肯定会在 Spring Container 中注册 bean。让我知道这是否有帮助:)

【讨论】:

  • 尝试在 mvc-dispatcher-service.xml 中声明 PlayerDAO bean 并将 autowire 属性设置为“byName”。让我知道。
  • 也没有帮助。但我更喜欢使用组件扫描而不是一一声明 bean。
  • 好的,请尝试一件事,将@Component注解放在PlayerDAO的顶部以及您调用自动连接bean PlayerDAO的类的顶部,即LoginRestService并让我知道结果!!
  • 仍然 playerDAO 为空并且正在产生 NPE。
  • 是的。我的意思是 playerDAO。
【解决方案5】:

我已经检查了你的代码,我得到了你的问题的答案。

您的代码没有任何问题。

但是当你想同时使用 spring mvc 和 jersey restfull webservices 时,你必须做一些比你在这里做的更多的事情。 Bcoz jersey 不知道 spring 容器及其实现。因此,每当您请求 web 服务球衣时,您的请求处理就会完全满足您的请求,而不是 spring 框架。

所以,这里 playerDao 没有注入到 LoginRestService.java 中,因此它 (playerDao) 解析为 null。

所以请执行以下步骤,

第 1 步:-- 将以下 maven 依赖项添加到您的 pom.xml

    <dependency>
        <groupId>com.sun.jersey.contribs</groupId>
       <artifactId>jersey-spring</artifactId>
        <version>1.19.1</version>
   <dependency>

这个依赖是用来集成Spring和Jersey

第 2 步:- 现在创建一个 WebApplicationContext 以从您的 mvc-dispatcher-servlet.xml 中读取所有配置信息。为此,将以下代码复制到您的 web.xml

<context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

第 3 步:-- 现在使用 jersey 框架提供的类 com.sun.jersey.spi.spring.container.servlet.SpringServlet 集成 spring 和 jersey(此类在 jersey-spring.jar 中可用)。为此,将以下代码复制到您的 web.xml

<servlet>
        <servlet-name>jersey-serlvet</servlet-name>

        <servlet-class>
            com.sun.jersey.spi.spring.container.servlet.SpringServlet
        </servlet-class>

        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>ngdemo.rest</param-value>
        </init-param>

        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>

        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>jersey-serlvet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

就是这样。一切都完成了。

只需更新您的 maven 项目并在服务器中再次运行。

建议 当您添加依赖项( jersey-spring-1.19.1.jar )时,还有一件事是一些与 spring 相关的 jar 文件(如 spring-aop.3.0.0CR.jar、spring-bean.jar 等)包含在您的 maven 中依赖项和包含的 jar 是旧版本。所以有时你可能会得到 ClassNotFoundException。所以你必须排除那些 spring 依赖项。 如果您遇到此类异常,请将以下代码复制到 jersey-spring.jar 的 元素

<dependency>
    <groupId>com.sun.jersey.contribs</groupId>
    <artifactId>jersey-spring</artifactId>
    <version>1.19.1</version>
    <exclusions>
        <exclusion>
            <artifactId>spring-context</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-core</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-beans</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-web</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
        <exclusion>
            <artifactId>spring-aop</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
    </exclusions>
</dependency>

我希望这对你有帮助。让我知道你是否得到了正确的解决方案。

【讨论】:

    猜你喜欢
    • 2022-01-04
    相关资源
    最近更新 更多