英文:
NullPointerException during bean creation in Spring
问题
我在一个带有@Bean
注解的方法中收到了一个NullPointerException,但之前从未在这个方法中遇到过这个NullPointerException:
Caused by: org.springframework.beans.BeanInstantiationException: 实例化[dev.teamnight.command.CommandFramework]失败:涉及包含bean 'config'的循环引用 - 考虑将工厂方法声明为静态,以使其独立于包含实例。 工厂方法'commandFramework'引发异常;嵌套异常是java.lang.NullPointerException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
... 68 common frames omitted
Caused by: java.lang.NullPointerException: null
at dev.teamnight.nightbot.Config.commandFramework(Config.java:84) ~[classes/:na]
at dev.teamnight.nightbot.Config$$EnhancerBySpringCGLIB$$2d4937ec.commandFramework(<generated>) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
... 69 common frames omitted
引发异常的文件的代码:
@Configuration
@PropertySource("file:bot.properties")
public class Config {
@Autowired
private ShardManager shardManager;
// 省略其他的@Autowired注入
@Bean
public CommandFramework commandFramework() {
Logger log = LogManager.getLogger();
// 下面这行引发了错误!
log.error("helpProvider的名称:" + this.helpProvider.getClass().getCanonicalName());
return new FrameworkBuilder()
.addOwners(Arrays.stream(this.ownerIds).filter(ownerId -> ownerId.matches("^(\\d)+$")).map(ownerId -> Long.parseLong(ownerId)).collect(Collectors.toList()))
.setLogger(NightBot.logger())
.allowBots(false)
.allowDM(false)
.allowMention(true)
.allowRainbowColors(true)
.withPrefixProvider(this.prefixProvider)
.withLanguageProvider(this.languageProvider)
.withPermissionProvider(this.permissionProvider)
.withHelpProvider(this.helpProvider)
.withCustomArgumentProcessor(new NamedArgumentProcessor())
.registerClient(this.shardManager)
.build();
}
}
如我所说,之前代码是完全工作的,而且我在Config.java
文件中没有做任何更改,所以这个错误真的让我很困惑。
英文:
I'm receiving a NullPointerException in a method with the Annotation @Bean
, but before I never got this NullPointerException there:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [dev.teamnight.command.CommandFramework]: Circular reference involving containing bean 'config' - consider declaring the factory method as static for independence from its containing instance. Factory method 'commandFramework' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
... 68 common frames omitted
Caused by: java.lang.NullPointerException: null
at dev.teamnight.nightbot.Config.commandFramework(Config.java:84) ~[classes/:na]
at dev.teamnight.nightbot.Config$$EnhancerBySpringCGLIB$$2d4937ec.CGLIB$commandFramework$3(<generated>) ~[classes/:na]
at dev.teamnight.nightbot.Config$$EnhancerBySpringCGLIB$$2d4937ec$$FastClassBySpringCGLIB$$3fbdfefd.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) ~[spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
at dev.teamnight.nightbot.Config$$EnhancerBySpringCGLIB$$2d4937ec.commandFramework(<generated>) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
... 69 common frames omitted
The code of the file causing the Exception:
@Configuration
@PropertySource("file:bot.properties")
public class Config {
@Autowired
private ShardManager shardManager;
@Autowired
private PermissionProvider permissionProvider;
@Autowired
private LanguageProvider languageProvider;
@Autowired
private PrefixProvider prefixProvider;
@Autowired
private HelpProvider helpProvider;
@Bean
public ShardManager shardManager() throws LoginException, IllegalArgumentException {
DefaultShardManagerBuilder builder = DefaultShardManagerBuilder.createDefault(this.botToken)
.enableIntents(GatewayIntent.GUILD_MEMBERS)
.setMemberCachePolicy(MemberCachePolicy.ALL)
.setStatus(OnlineStatus.IDLE)
.setShardsTotal(this.totalShards)
.addEventListeners(Arrays.asList(this.jdaListener()));
return builder.build();
}
@Bean
public CommandFramework commandFramework() {
Logger log = LogManager.getLogger();
//Line causing the error below!
log.error("Name of helpProvider: " + this.helpProvider.getClass().getCanonicalName());
return new FrameworkBuilder()
.addOwners(Arrays.stream(this.ownerIds).filter(ownerId -> ownerId.matches("^(\\d)+$")).map(ownerId -> Long.parseLong(ownerId)).collect(Collectors.toList()))
.setLogger(NightBot.logger())
.allowBots(false)
.allowDM(false)
.allowMention(true)
.allowRainbowColors(true)
.withPrefixProvider(this.prefixProvider)
.withLanguageProvider(this.languageProvider)
.withPermissionProvider(this.permissionProvider)
.withHelpProvider(this.helpProvider)
.withCustomArgumentProcessor(new NamedArgumentProcessor())
.registerClient(this.shardManager)
.build();
}
}
As I said, before the code fully worked, and I changed nothing on the Config.java file, so this error is confusing me as hell.
答案1
得分: 1
你看到这个 NullPointerException
是因为自动注入的 HelperProvider
没有被注入进来。
你正试图在一个空对象上调用 .getClass()
方法。
通用依赖注入调试
只是想快速地提到一些基本的事项,因为对这个问题的主要回答必须对你的代码库做一些假设。在依赖注入失败时,有几件事情你需要检查。
- 配置文件 - 这些是否被正确加载?你最近是否禁用了组件扫描?
- 你的
组件(Components)
是否有必要的@Component
,或者@Service/@Controller/@Repository
注解?
可能的根本问题 - 循环引用 - BeanInstantiationException
你的堆栈跟踪中还提到了循环引用,这很可能是导致问题的原因。
Caused by: org.springframework.beans.BeanInstantiationException: Circular reference involving containing bean 'config' - consider declaring the factory method as static for independence from its containing instance. Factory method 'commandFramework' threw exception; nested exception is java.lang.NullPointerException
由于你收到了这个错误消息,说明你引入了循环引用。这意味着......一个组件依赖于另一个组件,而后者又依赖于第一个组件。
例如:
@Component
class HelperProvider {
@Autowired
Config config;
}
和
@Configuration
class Config {
@Autowired
HelperProvider helperProvider
}
这种模式会让 Spring 框架陷入困境,因为它们彼此依赖于加载每个组件。如果你在后面引入了一个依赖关系,就会发生这种情况。比如 HelperProvider 需要 HelperHelperProvider,而 HelperHelperProvider 又需要 Config。
你需要检查最近的编辑中是否有对 Config
或 CommandFramework
的任何新注入。
你应该做什么
你应该重新设计你的配置,以打破对 HelperProvider
的依赖。这样做可以解决未来很多头疼的问题。
你不应该做什么
你可以使用 @Lazy
注解来延迟加载组件或配置。这样,只有在调用时才会实例化该 bean。如果你想要了解更多关于启动 Spring ApplicationContext
的微妙之处,这是推荐的方法,但是后期维护可能会变得非常困难。
英文:
You are seeing this NullPointerException
because the autowired HelperProvider
not being injected in.
You are attempting to call .getClass()
on a null object.
General Dependency Injection Debugging
Just want to add a quick basic mentions, since the main answer to this question has to make some assumption on your codebase. There are several things that you want to check when dependency injection fails.
- Configuration files - Are these being loaded in correctly. Is your component scanning recently disabled?
- Do your
Components
have the necessary@Component
and or@Service/@Controller/@Repository
annotations?
The Likely Root Problem - Circular Reference - BeanInstantiationException
There is also a mention of a circular reference in your stacktrace which is likely what is causing the problem.
Caused by: org.springframework.beans.BeanInstantiationException: Circular reference involving containing bean 'config' - consider declaring the factory method as static for independence from its containing instance. Factory method 'commandFramework' threw exception; nested exception is java.lang.NullPointerException
Since you received this error message, you have introduced a circular reference. This means... that a component relies on a component which relies on that component.
For example:
@Component
class HelperProvider {
@Autowired
Config config;
}
and
@Configuration
class Config {
@Autowired
HelperProvider helperProvider
}
This pattern will stump the spring framework because they rely on each other to load each component up. It can happen if you introduce a dependency further down the line. Say HelperProvider requires HelperHelperProvider which requires Config.
You will want to check for any new injections of Config
or CommandFramework
in your recent edits.
What you should do
You will want to redesign your configuration to break it's reliance on the HelperProvider
. Doing this can resolve a lot of headaches in your future.
What you shouldn't do
It's possible to lazyload the component or configuration with @Lazy
annotation. That way the bean is only instantiated upon invocation. It's recommended if you want to learn more nuances in booting up the Spring ApplicationContext
, but it will become a nightmare to maintain down the road.
答案2
得分: 0
你遇到的错误很可能是因为项目中存在循环依赖。由于你在错误中所示的commandFramework方法中遇到了这个错误,原因是HelpProvider类中再次使用了Config类。
因此,当Spring创建Config的bean时,它必须创建HelpProvider的bean,而后者又希望创建Config的bean(在HelpProvider中进行了@Autowired),从而导致无休止的循环,产生错误。还要检查HelpProvider是否具有@Component注解。
Config -> HelpProvider -> Config -> HelpProvider -> Config .............
解决方案:-
- 你可以将HelpProvider中的config移除,并尝试重新设计它。
- 在HelpProvider中对Config使用@Lazy注解,这将在对象实例化时加载此依赖项。建议将其作为最后的选择。
英文:
The error you are getting is most probably because you have a cyclic dependency in your project. And since you are getting it in commandFramework method as illustrated in error it is because of the HelpProvider class in which you are using the Config class again.
So when spring is creating a bean of Config it has to create a bean of HelpProvider which in terms wants to create a bean of Config(Autowired in HelpProvider) and leads to a never ending cycle giving the error. Also check if HelpProvider has the @component annotataion.
Config -> HelpProvider -> Config -> HelpProvider -> Config .............
Solution:-
- Either you can remove the config from the HelpProvider and try to redesign it.
- Use @Lazy on Config in HelpProvider which will load this dependency on object instantiation. Will suggest it as a last resort.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论