自动装配 Spring Bean 在抽象父级中为 null class
Autowired Spring Bean is null in abstract parent class
我有一个 Bean 负责从配置文件加载项目设置,并使它们可供可能需要它们的任何其他对象使用:
@Component
public class ProjectSettings extends Settings{[...]}
现在,我有一堆组件 classes,它们经过多个步骤扩展了一个抽象 class,我想在其中使用这个 bean:
@Component
public class SomeDataDbEditor extends MongoDbEditor<SomeData> {[...]}
public abstract class MongoDbEditor<T extends MongodbEntryInterface> extends MongoDbTypedAccessor<T>{[...]}
public abstract class MongoDbTypedAccessor<T extends MongodbEntryInterface> extends MongoDbAccessor {[...]}
public abstract class MongoDbAccessor {
@Autowired
protected ProjectSettings projectSettings;
public MongoDbAccessor() throws DatabaseNotConnectedException {
String databaseName = projectSettings.getMongodbDatabaseName();
[...]
}
根据我的理解,这应该可行,因为@Autowired 字段受到保护,因此可以从@Component class SomeDataDbEditor
中看到。但是,我得到了这个例外:
java.lang.IllegalStateException: Failed to load ApplicationContext
[...]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.company.project.module.some_data.database.accessor.SomeDataDbEditor]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:217)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:117)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:310)
... 124 more
Caused by: java.lang.NullPointerException
at io.company.project.module.database.accessor.MongoDbAccessor.<init>(MongoDbAccessor.java:26)
at io.company.project.module.database.accessor.MongoDbTypedAccessor.<init>(MongoDbTypedAccessor.java:20)
at io.company.project.module.database.accessor.MongoDbEditor.<init>(MongoDbEditor.java:19)
at io.company.project.module.some_data.database.accessor.SomeDataDbEditor.<init>(SomeDataDbEditor.java:17)
...引用的 MongoDbAccessor.<init>(MongoDbAccessor.java:26)
行是 String databaseName = projectSettings.getMongodbDatabaseName();
现在,我已经确认 projectSettings
字段在那种情况下确实为空。但是,我还能够确认,如果我尝试访问 SomeDataDbEditor
中的 ProjectSettings
bean,那是有效的,并且 bean 得到了正确的实例化。
我知道此时一个可能的解决方案是使用它并手动将 ProjectSettings
bean 传递给父 classes,但这有点违背了使用的意义首先是依赖注入。此外,我将不得不为此进行调整,真的,真的很多 classes,我想尽可能避免这种情况。
那么,有没有人知道为什么会发生这种情况,我可以采取什么措施来应对它?
如果您使用字段注入(字段自动装配),则不能在构造函数中使用这些字段,因为 Spring 只能在构造对象后注入依赖项,即在所有构造函数完成后。
为了避免这种情况,您要么必须更改为构造函数注入,要么在构造函数中执行的初始化工作,在一个单独的方法中用 PostConstruct 注释:
@javax.annotation.PostConstruct
public void initialize() {
}
但是如果您能够将代码更改为构造函数注入,我(以及 Spring 宇宙中的许多其他人)强烈推荐它,因为它可以防止此类问题。
我有一个 Bean 负责从配置文件加载项目设置,并使它们可供可能需要它们的任何其他对象使用:
@Component
public class ProjectSettings extends Settings{[...]}
现在,我有一堆组件 classes,它们经过多个步骤扩展了一个抽象 class,我想在其中使用这个 bean:
@Component
public class SomeDataDbEditor extends MongoDbEditor<SomeData> {[...]}
public abstract class MongoDbEditor<T extends MongodbEntryInterface> extends MongoDbTypedAccessor<T>{[...]}
public abstract class MongoDbTypedAccessor<T extends MongodbEntryInterface> extends MongoDbAccessor {[...]}
public abstract class MongoDbAccessor {
@Autowired
protected ProjectSettings projectSettings;
public MongoDbAccessor() throws DatabaseNotConnectedException {
String databaseName = projectSettings.getMongodbDatabaseName();
[...]
}
根据我的理解,这应该可行,因为@Autowired 字段受到保护,因此可以从@Component class SomeDataDbEditor
中看到。但是,我得到了这个例外:
java.lang.IllegalStateException: Failed to load ApplicationContext
[...]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.company.project.module.some_data.database.accessor.SomeDataDbEditor]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:217)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:117)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:310)
... 124 more
Caused by: java.lang.NullPointerException
at io.company.project.module.database.accessor.MongoDbAccessor.<init>(MongoDbAccessor.java:26)
at io.company.project.module.database.accessor.MongoDbTypedAccessor.<init>(MongoDbTypedAccessor.java:20)
at io.company.project.module.database.accessor.MongoDbEditor.<init>(MongoDbEditor.java:19)
at io.company.project.module.some_data.database.accessor.SomeDataDbEditor.<init>(SomeDataDbEditor.java:17)
...引用的 MongoDbAccessor.<init>(MongoDbAccessor.java:26)
行是 String databaseName = projectSettings.getMongodbDatabaseName();
现在,我已经确认 projectSettings
字段在那种情况下确实为空。但是,我还能够确认,如果我尝试访问 SomeDataDbEditor
中的 ProjectSettings
bean,那是有效的,并且 bean 得到了正确的实例化。
我知道此时一个可能的解决方案是使用它并手动将 ProjectSettings
bean 传递给父 classes,但这有点违背了使用的意义首先是依赖注入。此外,我将不得不为此进行调整,真的,真的很多 classes,我想尽可能避免这种情况。
那么,有没有人知道为什么会发生这种情况,我可以采取什么措施来应对它?
如果您使用字段注入(字段自动装配),则不能在构造函数中使用这些字段,因为 Spring 只能在构造对象后注入依赖项,即在所有构造函数完成后。
为了避免这种情况,您要么必须更改为构造函数注入,要么在构造函数中执行的初始化工作,在一个单独的方法中用 PostConstruct 注释:
@javax.annotation.PostConstruct
public void initialize() {
}
但是如果您能够将代码更改为构造函数注入,我(以及 Spring 宇宙中的许多其他人)强烈推荐它,因为它可以防止此类问题。