简体   繁体   English

自动装配的 Spring Bean 是抽象父 class 中的 null

[英]Autowired Spring Bean is null in abstract parent class

I have a Bean that is responsible for loading the project settings from a config file, and making them available to any other object that might need them:我有一个 Bean,负责从配置文件加载项目设置,并使它们可用于可能需要它们的任何其他 object:

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

Now, I have a bunch of component classes that over multiple steps extend an abstract class where I want to use this bean in:现在,我有一堆组件类,它们通过多个步骤扩展了一个抽象 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();
        [...]
}

From my understanding, this should work since the @Autowired field is protected and thus visible from the @Component class SomeDataDbEditor .据我了解,这应该可以工作,因为 @Autowired 字段受到保护,因此可以从 @Component class SomeDataDbEditor中看到。 However, instead I get this exception:但是,相反,我得到了这个异常:

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)

...where the referenced MongoDbAccessor.<init>(MongoDbAccessor.java:26) line is String databaseName = projectSettings.getMongodbDatabaseName(); ...其中引用的MongoDbAccessor.<init>(MongoDbAccessor.java:26)行是String databaseName = projectSettings.getMongodbDatabaseName();

Now, I have confirmed that the projectSettings field really is null in that case.现在,我已经确认projectSettings字段在这种情况下确实是 null。 However, I was also able to confirm that if I try to access the ProjectSettings bean in the SomeDataDbEditor , that works, and the bean gets correctly instantiated.但是,我也能够确认,如果我尝试访问SomeDataDbEditor中的ProjectSettings bean,它会起作用,并且 bean 会被正确实例化。

I know that one possible solution at this point would be to use that and just manually pass the ProjectSettings bean to the parent classes, but that would kind of defeat the point of using dependency injection in the first place.我知道此时一个可能的解决方案是使用它并手动将ProjectSettings bean 传递给父类,但这会破坏首先使用依赖注入的意义。 Also, I would have to adjust, like, really, really many classes for that, and I want to avoid that if at all possible.此外,我将不得不为此调整,非常非常多的课程,如果可能的话,我想避免这种情况。

So, does anyone have an idea why this happens here, and what I can do against it?那么,有谁知道为什么会在这里发生这种情况,以及我能做些什么呢?

If you use field injection (Autowired on fields), you cannot use those fields in the constructor, since Spring can only inject the dependencies after the object was constructed, ie after all constructors have finished.如果使用字段注入(Autowired on fields),则不能在构造函数中使用这些字段,因为 Spring 只能在 object 构造完成后(即所有构造函数完成后)注入依赖项。

To circumvent that, you would either have to change to constructor injection, or alternatively do the initialization work, that you do in the constructor, in a separate method annotated with PostConstruct:为了避免这种情况,您必须更改为构造函数注入,或者在构造函数中执行的初始化工作,在使用 PostConstruct 注释的单独方法中:

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

}

But if you are able to change your code to constructor injection, i (as well as a lot of other people in the Spring universe) highly recommend it, since it prevents exactly such problems.但是,如果您能够将代码更改为构造函数注入,我(以及 Spring 领域中的许多其他人)强烈推荐它,因为它可以防止此类问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM