You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot迁移至Ubuntu后ApplicationContextProvider抛出NullPointerException

问题

Spring Boot 3.2.4应用在Windows 10/Server 2019上运行正常,但迁移至Ubuntu 24.04后,调用ApplicationContextProvider.getApplicationContext()抛出NullPointerException,所有环境均使用openjdk-18.0.1。

相关代码

ApplicationContextProvider(实现ApplicationContextAware)

@Component
public class ApplicationContextProvider implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
        ApplicationContextProvider.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
}

报错触发类MainBuilderUtil

@Component
public class MainBuilderUtil {
    MainChannelCredentialsUtil mainChannelCredentialsUtil;

    public final OAuth2Credential credentialMain = new OAuth2Credential("provider",
            ApplicationContextProvider.getApplicationContext().getBean(MainChannelCredentialsUtil.class).getMainToken());

    @Autowired
    private MainBuilderUtil(MainChannelCredentialsUtil mainChannelCredentialsUtil) {
        this.mainChannelCredentialsUtil = mainChannelCredentialsUtil;
    }

    public final Client ClientMain =
            ClientBuilder.builder()
                    .withEnableChat(true)
                    .withChatAccount(credentialMain)
                    .build();

    //getters
}

报错堆栈信息

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.bot.springbootbot.connections.channels.builder_utils.MainBuilderUtil]: Constructor threw exception
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:221) ~[spring-beans-6.1.5.jar!/:6.1.5]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:111) ~[spring-beans-6.1.5.jar!/:6.1.5]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:315) ~[spring-beans-6.1.5.jar!/:6.1.5]
    ... 24 common frames omitted
Caused by: java.lang.NullPointerException: Cannot invoke "org.springframework.context.ApplicationContext.getBean(java.lang.Class)" because the return value of "com.bot.springbootbot.ApplicationContextProvider.getApplicationContext()" is null
    at com.bot.springbootbot.connections.channels.builder_utils.MainBuilderUtil.<init>(MainBuilderUtil.java:18) ~[!/:0.0.1-SNAPSHOT]
    at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) ~[na:na]
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502) ~[na:na]
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486) ~[na:na]
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:208) ~[spring-beans-6.1.5.jar!/:6.1.5]
    ... 26 common frames omitted

启动警告信息

WARN 6417 --- [SpringBootBot] [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mainBuilderUtil' defined in URL [jar:nested:/usr/SpringBootBot/target/SpringBootBot-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/com/bot/springbootbot/connections/channels/builder_utils/MainBuilderUtil.class]: Failed to instantiate [com.bot.springbootbot.connections.channels.builder_utils.MainBuilderUtil]: Constructor threw exception

已知该类无需作为Spring Bean,但此前Windows环境可行,更换JDK无效,需明确跨系统报错原因及解决办法。


原因分析与解决办法

核心原因

Windows与Linux环境下Spring Bean的初始化顺序存在差异。Windows环境中ApplicationContextProvider恰好先于MainBuilderUtil完成初始化,静态变量被赋值;但Ubuntu环境中,MainBuilderUtil的实例化(包含成员变量credentialMain的初始化)早于ApplicationContextProvider的setApplicationContext方法执行,导致静态applicationContext为null,触发空指针异常。

这种依赖初始化顺序的实现本身不具备稳定性,Windows环境能运行只是巧合,并非正确写法。

解决办法

方案1:移除Spring Bean管理,手动初始化(推荐,符合你提到的该类无需作为Bean的需求)

  1. 删除MainBuilderUtil上的@Component注解,不再让Spring接管该类的实例化。
  2. 修改代码,通过构造函数传入依赖,彻底避免依赖静态上下文:
public class MainBuilderUtil {
    private final MainChannelCredentialsUtil mainChannelCredentialsUtil;
    public final OAuth2Credential credentialMain;
    public final Client ClientMain;

    public MainBuilderUtil(MainChannelCredentialsUtil mainChannelCredentialsUtil) {
        this.mainChannelCredentialsUtil = mainChannelCredentialsUtil;
        this.credentialMain = new OAuth2Credential("provider", mainChannelCredentialsUtil.getMainToken());
        this.ClientMain = ClientBuilder.builder()
                .withEnableChat(true)
                .withChatAccount(credentialMain)
                .build();
    }

    // getters
}
  1. 在需要使用MainBuilderUtil的Spring Bean中,通过注入的MainChannelCredentialsUtil手动创建实例:
@Autowired
private MainChannelCredentialsUtil credentialsUtil;

public void businessMethod() {
    MainBuilderUtil builderUtil = new MainBuilderUtil(credentialsUtil);
    // 使用builderUtil完成业务逻辑
}

方案2:保留Spring Bean,修正初始化时机

如果必须让Spring管理MainBuilderUtil,则需要避免在成员变量初始化阶段依赖静态上下文,改用@PostConstruct注解在Bean完全初始化后执行逻辑:

@Component
public class MainBuilderUtil {
    @Autowired
    private MainChannelCredentialsUtil mainChannelCredentialsUtil;

    public OAuth2Credential credentialMain;
    public Client ClientMain;

    @PostConstruct
    public void init() {
        this.credentialMain = new OAuth2Credential("provider", mainChannelCredentialsUtil.getMainToken());
        this.ClientMain = ClientBuilder.builder()
                .withEnableChat(true)
                .withChatAccount(credentialMain)
                .build();
    }

    // getters
}

此方式下,credentialMain和ClientMain会在Spring完成mainChannelCredentialsUtil注入,且整个Bean初始化完成后再初始化,彻底摆脱对不稳定初始化顺序的依赖。


内容的提问来源于stack exchange,提问作者maximuz666

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 14:24:54