自动装配 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 宇宙中的许多其他人)强烈推荐它,因为它可以防止此类问题。