如何在 ApplicationListener 中初始化 autowire 对象?
How to make autowire object initialized in ApplicationListener?
我想读取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>
{ }
问题
As you can see in my code, at InitData(), repository is null. I don't
know why @Autowired MyElasticsearchRepository repository;
does not
worked here.
请告诉我如何解决这个问题。非常感谢。
@Autowired
仅在 bean 标记有 Stereotype 注释(What's the difference between @Component, @Repository & @Service annotations in Spring?)或您在 spring 配置中明确定义它时才有效。
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
//.......
}
}
@Autowired 只有在构建 AppContext 对象后才会起作用。由于您尝试在构造函数中访问 @Autowired 元素,因此它不存在。
您的代码有几处错误。
首先,您使用的是单例模式,我认为这是一种反模式,尤其是与自动布线结合使用时。
其次,在您的 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
。不要从构造函数调用方法,而是使用构造函数注入或使用 @PostConstruct
.
注释 InitData
方法
@PostConstruct
private void InitData(){
List<MyEntity> dataList = repository.findAllEntities();
...
}
既然你的 AppContext
是一个组件,它将被 spring 检测到,你可以简单地将它注入你的 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 为什么字段注入是邪恶的并且应该避免。
你就不能这样做吗?
@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
}
}
我想读取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>
{ }
问题
As you can see in my code, at InitData(), repository is null. I don't know why
@Autowired MyElasticsearchRepository repository;
does not worked here.
请告诉我如何解决这个问题。非常感谢。
@Autowired
仅在 bean 标记有 Stereotype 注释(What's the difference between @Component, @Repository & @Service annotations in Spring?)或您在 spring 配置中明确定义它时才有效。
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
//.......
}
}
@Autowired 只有在构建 AppContext 对象后才会起作用。由于您尝试在构造函数中访问 @Autowired 元素,因此它不存在。
您的代码有几处错误。
首先,您使用的是单例模式,我认为这是一种反模式,尤其是与自动布线结合使用时。
其次,在您的 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
。不要从构造函数调用方法,而是使用构造函数注入或使用 @PostConstruct
.
InitData
方法
@PostConstruct
private void InitData(){
List<MyEntity> dataList = repository.findAllEntities();
...
}
既然你的 AppContext
是一个组件,它将被 spring 检测到,你可以简单地将它注入你的 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 为什么字段注入是邪恶的并且应该避免。
你就不能这样做吗?
@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
}
}