我想在ApplicationListener中读取数据,但是我的对象未初始化。下面是我的代码:

AppContextListener.java

@Component
public class AppContextListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        AppContext.getInstance();
    }
}


AppContext.java

public class AppContext {
    private static AppContext instance;

    @Autowired
    MyElasticsearchRepository repository;

    public AppContext(){
        InitData();
    }

    public static synchronized AppContext getInstance() {
        if (instance == null) {
            instance = new AppContext();
        }
        return instance;
    }

    private void InitData(){
        List<MyEntity> dataList = repository.findAllEntities();//repository is null here
        //.......
    }
}


MyElasticsearchRepository.java

 public interface MyElasticsearchRepository extends ElasticsearchRepository<MyEntity,String>
 { }


问题


  正如您在我的代码中看到的那样,在InitData()处,存储库为null。我不
  知道为什么@Autowired MyElasticsearchRepository repository;
  在这里工作。


请告诉我如何解决此问题。非常感谢你。

最佳答案

您的代码有几处错误。

首先,您使用的是单例模式,我想说这是一种反模式,尤其是与自动布线结合使用时。

其次,在您的getInstance()方法中,您自己创建了AppContext的新实例。这个实例不是由Spring管理的,因此@Autowired在这里几乎没有用,Spring只能将依赖项注入它所知道的bean中。

而是将您的AppContext设为组件(或根据需要提供服务)。删除getInstance方法,改用构造函数注入。

@Component
public class AppContext {

    private final MyElasticsearchRepository repository;

    @Autowired
    public AppContext(MyElasticsearchRepository repository){
        this.repository=repository;
    }
    ...
}


第三,您尝试使用构造函数中的@Autowired实例(您正在进行方法调用,希望它在那里),但是只能在bean的实例上进行自动接线。因此,此时尚未进行自动接线,您的变量将始终为null。不用从构造函数调用方法,而是使用构造函数注入或用InitData注释@PostConstruct方法。

@PostConstruct
private void InitData(){
    List<MyEntity> dataList = repository.findAllEntities();
    ...
}


现在,您的AppContext是组件,它将在春季被检测到,您只需将其注入到您的ApplicationListener中即可。

@Component
public class AppContextListener implements ApplicationListener<ContextRefreshedEvent> {

    private final AppContext appContext;

    @Autowired
    public AppContextListener(AppContext appContext) {
        this.appContext=appContext;
    }
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        // Do your thing with appContext
    }
}


注意:我更喜欢将构造函数注入用于必填字段,将setter注入用于可选字段。您应避免字段注入(即实例字段上的@Autowired),因为这被认为是不好的做法。参见here为什么电场注入是有害的,应该避免。

09-04 02:50