首页 > 解决方案 > Autowired 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在这种情况下该字段确实为空。但是,我还能够确认,如果我尝试访问ProjectSettingsbean 中的 bean SomeDataDbEditor,它会起作用,并且 bean 会被正确实例化。

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

那么,有谁知道为什么会在这里发生这种情况,以及我能做些什么呢?

标签: javaspringdependency-injection

解决方案


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

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

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

}

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


推荐阅读