简体   繁体   中英

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:

@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:

@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 . 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();

Now, I have confirmed that the projectSettings field really is null in that case. 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.

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. 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.

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:

@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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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