如何在ApplicationListener中初始化autowire对象?

时间:2015-05-26 09:27:36

标签: java spring javabeans

我想在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;没有   在这里工作。

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

4 个答案:

答案 0 :(得分:1)

只有在使用Stereotype注释(What's the difference between @Component, @Repository & @Service annotations in Spring?)标记bean或在spring配置中明确定义它时,

@Autowired才有效。

<强> AppContextListener.java

@Component // AFAIR not needed. Spring will create this bean when it will see that class implements `ApplicationListener` interface.
public class AppContextListener implements ApplicationListener<ContextRefreshedEvent> {
    @Autowired
    private AppContext appContext;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {       
        appContext.initData();
    }
}

<强> AppContext.java

@Component
public class AppContext {    

    @Autowired
    MyElasticsearchRepository repository;

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

答案 1 :(得分:1)

您的代码存在一些问题。

首先,您使用的是单一模式,我认为这是一种反模式,特别是与自动接线结合使用时。

您的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为什么现场注射是邪恶的,应该避免。

答案 2 :(得分:0)

@Autowired仅在构造AppContext对象后才起作用。由于您尝试在构造函数中访问@Autowired元素,因此它不存在。

答案 3 :(得分:0)

你不能这样做吗?

    @Component
    public class AppContextListener implements ApplicationListener<ContextRefreshedEvent> {
        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {       
            ApplicantContext context = event.getApplicationContext();
            MyElasticsearchRepository repository = context.getBean(MyElasticSearchRepository.class);
            //do stuff
        }
    }

http://docs.spring.io/autorepo/docs/spring/4.1.4.RELEASE/javadoc-api/org/springframework/context/event/ContextRefreshedEvent.html