【问题标题】:Autowiring for @Service field failed@Service 字段的自动装配失败
【发布时间】:2018-01-02 13:00:13
【问题描述】:

我整天都在查看我的代码,但找不到原因。存储库 (@Repository) 工作得很好,我一直失败的是 @Service 字段让它自动装配,我一直在努力,因为一切看起来都很好

分派的servlet:

<mvc:annotation-driven />
<context:component-scan base-package="com" /> 

com.repository

Repo.java

package com.repository;
import com.domain.Student;
import java.util.List;

public interface Repo { public List<Student> getAllSiswa();  }

RepoImplement.java

import com.domain.Student;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Repository;

@Repository
public class RepoImplement implements Repo {
 List<Student> ls = new ArrayList<>();

public RepoImplement(){  
        Student s1 = new Student();
        s1.setNama("paul");

        Student s2 = new Student();
        s2.setNama("robert");

        ls.add(s1);
        ls.add(s2);
}

    @Override
    public List<Student> getAllSiswa() {    
       return this.ls;
    }
}

打包 com.service;

Serve.java

import com.domain.Student;
import java.util.List;

public interface Serve {
    void changeName(String namaBaru);
    public List<Student> newList();
}

我怀疑这里有问题

ServeImplement.java

import com.domain.Student;
import com.repository.Repo;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ServeImplement implements Serve {
    @Autowired
    public Repo repo;  
    List<Student> s = repo.getAllSiswa(); // THIS IS SUSPECTING ME.

    @Override
    public void changeName(String namaBaru) {
        s.get(0).setNama(namaBaru); // get first Student, then update its name.
      }
    @Override
    public List<Student> newList() {
        return this.s;
    }
}

controller2.java是服务学生的映射请求

package com.controlller;
import com.domain.Student;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.service.Serve;

@Controller
public class controller2 {

    @Autowired
    public Serve serv;

    @RequestMapping("/changename")
    public ModelAndView sdaf() {
        serv.changeName("New name");
        List<Student> list = serv.newList();
        return new ModelAndView("page2", "out", list);
    }
}

错误:

创建名为“controller2”的 bean 时出错:注入自动装配 依赖失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:不能 自动装配字段:公共 com.service.Serve com.controller.controller2.serv;嵌套异常是 org.springframework.beans.factory.BeanCreationException:错误 创建文件中定义的名称为“serveImplement”的bean [C:\Users\hans\Documents\NetBeansProjects\WebApplication2\build\web\WEB-INF\classes\com\service\ServeImplement.class]: bean 实例化失败;嵌套异常是 org.springframework.beans.BeanInstantiationException:不能 实例化 bean 类 [com.service.ServeImplement]:构造函数抛出 例外;嵌套异常是 java.lang.NullPointerException

【问题讨论】:

  • 是的。 repo 可以是 null。您在堆栈跟踪中看到 NPE 吗?
  • @VinodMadyalkar,感谢您的回复,是的,List&lt;Student&gt; s = repo.getAllSiswa(); 上的指针为空,但我找不到原因,因为它看起来连接正确..
  • repo.getAllSiswa();放入标记为@PostConstruct的方法中
  • @VinodMadyalkar,在RepoImplement 之后的@Override ??
  • 没有。在ServeImplement :)

标签: java spring spring-mvc


【解决方案1】:

您需要了解自动装配,或者实际上是一般的 Java,是如何工作的。

Spring 必须创建 ServImpl 类的实例,并使用存储库 bean 填充字段 repo。它使用反射来做到这一点,但它所做的基本上等同于以下代码:

ServImpl s = new ServImpl();
s.repo = theRepoBean;

所以,你会看到s.repo 在构造函数执行后 变为非空。并且,在执行构造函数时,会执行以下代码行:

List<Student> s = repo.getAllSiswa();

此时,repo 尚未初始化。所以它是空的。所以你会得到一个 NullPointerException。

使用构造函数注入代替字段注入,或使用@PostConstruct 注释方法。

请把你的字段设为私有而不是公开。

也就是说,存储库的目标通常是从数据库中获取数据。并且可以在数据库中修改、删除或创建学生。因此,初始化服务的一个字段并始终返回相同的列表会破坏拥有 repo 的全部意义。您应该在每次调用 newList() 时调用 repo.getAllSiswa(),以获取最新的学生列表。

【讨论】:

  • 是的,这就是我想到的一秒钟......但让我先试试吧。
  • 很抱歉,如果这是一个有趣的问题,但 StudentRepoImplement 构造函数中初始化,然后 @Autowired public Repo repo; 在那里,不会为空。或者我错过了什么..
  • 你似乎错过了我所有的答案。再读一遍。 null 是服务中的 repo 字段。与学生无关。
  • @AngryDumbassSlapper - 请看,当ServImpl 的构造发生时,repo 未初始化,因此将为空。你在它上面调用一个方法,所以你得到了 NPE。
  • 是的,它现在可以工作了,我将 @Autowired 放在构造函数上方。并在其中初始化了 List .. 非常感谢...伙计们(@VinodMadyalkar 谢谢兄弟..)
【解决方案2】:

因为Autowired on field 是在构造之后立即发生的,所以您需要更改代码才能使其正常工作。

这应该可行:

@Service
public class ServeImplement implements Serve {

    public Repo repo;
    List<Student> s;

    @Autowired
    public ServeImplement(Repo repo) {
        this.repo = repo;
        s = repo.getAllSiswa();
    }

    @Override
    public void changeName(String namaBaru) {
        s.get(0).setNama(namaBaru); // get first Student, then update its name.
    }

    @Override
    public List<Student> newList() {
        return this.s;
    }

}

此外,在构造函数上使用Autorwired 注释允许您将您的字段标记为final,如果实例不必更改。

【讨论】:

  • 谢谢@Fabian..,是的解决方案有效(这是JBNized答案的具体实现)..
猜你喜欢
  • 2012-11-20
  • 2016-08-17
  • 2013-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-25
  • 2018-02-21
  • 2012-05-19
相关资源
最近更新 更多