在 Spring 中创建 bean 期间发生 NullPointerException

NullPointerException during bean creation in Spring

我在带有注释 @Bean 的方法中收到 NullPointerException,但在此之前我从未在那里收到此 NullPointerException:

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$d4937ec.CGLIB$commandFramework(<generated>) ~[classes/:na]
        at dev.teamnight.nightbot.Config$$EnhancerBySpringCGLIB$d4937ec$$FastClassBySpringCGLIB$fbdfefd.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$d4937ec.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

导致异常的文件代码:

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

正如我所说,在代码完全运行之前,我对 Config.java 文件没有任何更改,所以这个错误让我很困惑。

你看到这个 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 需要 Config.

您需要在最近的编辑中检查 ConfigCommandFramework 的任何新注入。

你应该做什么

您需要重新设计您的配置以打破它对 HelperProvider 的依赖。这样做可以解决你以后很多头疼的问题。

你不应该做的事情

可以使用 @Lazy 注释延迟加载组件或配置。这样,bean 仅在调用时实例化。如果你想在启动时了解更多细微差别,推荐 Spring ApplicationContext,但维护起来将成为一场噩梦。

您遇到的错误很可能是因为您的项目中存在循环依赖。并且由于您在 commandFramework 方法中获取它,如错误所示,这是因为您在其中再次使用 Config class 的 HelpProvider class。

因此,当 spring 创建 Config 的 bean 时,它必须创建一个 HelpProvider 的 bean,换句话说,它想要创建一个 Config 的 bean(在 HelpProvider 中自动装配)并导致一个永无止境的循环,给出错误。还要检查 HelpProvider 是否有 @component 注释。

配置 -> HelpProvider -> 配置 -> HelpProvider -> 配置 ...............

解决方法:-

  1. 或者您可以从 HelpProvider 中删除配置并尝试重新设计它。
  2. 在 HelpProvider 的 Config 上使用 @Lazy,这将加载对对象实例化的依赖。将建议它作为最后的手段。