JavaSpring——为什么自动连线存储库在服务构造函数中为空?

JavaSpring——为什么自动连线存储库在服务构造函数中为空?,java,spring,repository,javabeans,autowired,Java,Spring,Repository,Javabeans,Autowired,我在测试一些东西时遇到了这种奇怪的行为 我想做什么 假设我想使用本地文件、请求或其他方式将一些值预加载到存储库中 通常我会把这些放在一个构造函数中,如下所示: @Service public class PointOfInterestService { @Autowired private PointOfInterestRepository pointOfInterestRepository; public PointOfInterestService() {

我在测试一些东西时遇到了这种奇怪的行为

我想做什么

假设我想使用本地文件、请求或其他方式将一些值预加载到存储库中

通常我会把这些放在一个构造函数中,如下所示:

@Service
public class PointOfInterestService {

    @Autowired
    private PointOfInterestRepository pointOfInterestRepository;

    public PointOfInterestService() {
        try {
            String jsonStr = Helper.isToString(new FileInputStream(new File("test.json")));
            JSONObject json = new JSONObject(jsonStr);
            JSONArray entries = json.getJSONArray("features");
            for (Object element : entries) {
                try {      
                        //new PointOfInterest(...) 
                        //read file and do stuff
                        //... 

                        //finally, let's save the object
                        this.registerPointOfInterest(pointOfInterest);
                    }
                } catch (Exception e) {
                    if (!(e instanceof JSONException)) {
                        e.printStackTrace();
                    }
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void registerPointOfInterest(PointOfInterest pointOfInterest) {
        pointOfInterestRepository.save(pointOfInterest);
    }
}
当构造函数运行时,每当抛出
registerPointOfInterest
时,就会弹出一个
NullPointerException

使用调试器,我意识到由于某种原因,存储库为null(因此引发异常)

这是repository类,非常简单:

package com.example.demo.PointOfInterest;

import org.springframework.data.jpa.repository.JpaRepository;


public interface PointOfInterestRepository extends JpaRepository<PointOfInterest, String> {
}

package com.example.demo.PointOfInterest;
导入org.springframework.data.jpa.repository.JpaRepository;
InterestRepository的公共接口点扩展了JpaRepository{
}

有什么简单的方法可以读取构造函数中的文件吗?谢谢!

如果您有一个构造函数,存储库将不会由Spring自动连接(因此服务本身不是单例)。您应该用其他方法更改构造函数。

您可以尝试以下方法:

@Service
public class PointOfInterestService {

private PointOfInterestRepository pointOfInterestRepository;

public PointOfInterestService(
       @Autowired PointOfInterestRepository pointOfInterestRepository
) {
    this.pointOfInterestRepository =  pointOfInterestRepository;
}
您还可以删除构造函数中的@Autowired,因为spring自动知道必须执行DI

@Service
public class PointOfInterestService {

private PointOfInterestRepository pointOfInterestRepository;

public PointOfInterestService(
       PointOfInterestRepository pointOfInterestRepository
) {
    this.pointOfInterestRepository =  pointOfInterestRepository;
}

对于任何感兴趣的人,我实际上通过删除构造函数并在私有方法上使用
@PostConstruct
注释解决了这个问题,如下所示:

 @PostConstruct
    private void readGeoJson() {
       ....
    }

谢谢大家!

您可以尝试在构造函数中传递存储库,而不是将其作为字段传递,因此spring现在必须在@Service执行构造函数之前创建/注入依赖项。因为应用程序上下文随机创建对象,所以它无法确保存储库对象是在@Service执行构造函数时创建的erestService执行其构造函数在对象已经构造之前,自动连接无法发生。这是始终使用构造函数注入的原因之一。此外,这是隐藏在构造函数中的大量初始化(您的测试将是一场噩梦!),将加载功能提取到
@Bean
方法中,并向构造函数提供预解析的
列表
,这将使每个人的生活更加轻松。@chrylis onstrike-我最终使用了
@PostConstruct
注释。有什么显著的缺点吗?@TheodorosTsigkanos它仍然埋下了很多漏洞逻辑很难测试的地方的复杂部分。这里有三个完全独立的步骤(加载输入流、转换为对象和连接到服务)注意,您可能应该使用Spring
资源,而不是
文件
,并且您可能可以使用类似于
mapper.readValue(Resource.getInputStream(),new TypeReference)的Jackson在一行中完成所有这一切;
@chrylis onstrike-谢谢你的提醒!我在Spring是个新手,所以很高兴能得到一些有用的反馈。不幸的是,我正在阅读的文件并没有真正格式化成可以直接解析成对象的格式(它包含许多可能嵌套或不嵌套的点),所以它需要一些手动过滤。不过我肯定会开始阅读有关资源的内容!