抽象父类中的自动装配 Spring Bean 为空

问题描述

我有一个 Bean,负责从配置文件加载项目设置,并使它们可用于可能需要它们的任何其他对象:

@Component
public class ProjectSettings extends Settings{[...]}

现在,我有一堆组件类,它们通过多个步骤扩展了一个抽象类,我想在其中使用这个 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 类 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 字段确实为空。但是,我也能够确认,如果我尝试访问 ProjectSettings 中的 SomeDataDbeditor bean,它会起作用,并且 bean 被正确实例化。

我知道此时一个可能的解决方案是使用它并手动将 ProjectSettings bean 传递给父类,但这首先会破坏使用依赖注入的意义。此外,我必须为此调整很多课程,如果可能的话,我想避免这种情况。

那么,有没有人知道为什么会在这里发生这种情况,我可以做些什么来对付它?

解决方法

如果你使用字段注入(Autowired on fields),你不能在构造函数中使用这些字段,因为 Spring 只能在对象被构造之后注入依赖,即在所有构造函数都完成之后。

要避免这种情况,您要么必须更改为构造函数注入,要么在构造函数中执行初始化工作,并在一个单独的方法中使用 PostConstruct 进行注释:

@javax.annotation.PostConstruct
public void initialize() {

}

但是如果您能够将代码更改为构造函数注入,我(以及 Spring 世界中的许多其他人)强烈推荐它,因为它可以防止此类问题。