空指针异常在Spring中创建bean时发生。

huangapple go评论72阅读模式
英文:

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() 方法。

通用依赖注入调试

只是想快速地提到一些基本的事项,因为对这个问题的主要回答必须对你的代码库做一些假设。在依赖注入失败时,有几件事情你需要检查。

  1. 配置文件 - 这些是否被正确加载?你最近是否禁用了组件扫描?
  2. 你的 组件(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。

你需要检查最近的编辑中是否有对 ConfigCommandFramework 的任何新注入。

你应该做什么

你应该重新设计你的配置,以打破对 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.

  1. Configuration files - Are these being loaded in correctly. Is your component scanning recently disabled?
  2. 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 .............

解决方案:-

  1. 你可以将HelpProvider中的config移除,并尝试重新设计它。
  2. 在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:-

  1. Either you can remove the config from the HelpProvider and try to redesign it.
  2. Use @Lazy on Config in HelpProvider which will load this dependency on object instantiation. Will suggest it as a last resort.

huangapple
  • 本文由 发表于 2020年8月24日 08:31:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/63553306.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定