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

Spring Boot @Async场景下直接访问字段报NullPointerException的原因

问题分析:Spring Boot中直接访问public字段抛出NPE,调用getter方法正常的原因

相关代码

@Service
public class Listener {
    public ConcurrentHashMap<String, String> bars;

    public Listener() {
        bars = new ConcurrentHashMap<>();
    }

    public ConcurrentHashMap<String, String> getBars() {
        return bars;
    }

    @Async
    public void addBars(CountDownLatch counter) {
        bars.put("hello", "world");
        counter.countDown();
    }
}

@RestController
public class Controller {
    @Autowired
    Listener listener;

    @GetMapping("/")
    public String trial() throws InterruptedException {
        CountDownLatch counter = new CountDownLatch(1);
        listener.addBars(counter);
        counter.await();
        return listener.bars.get("hello"); // 直接访问字段会NPE,换成getBars()就正常
    }
}

原因解析

  • Spring代理机制的影响:因为Listener类包含@Async注解的方法,Spring会为该类生成代理对象(默认用CGLIB代理,因为Listener是普通类未实现接口),以此实现异步逻辑。
  • 代理对象的字段未初始化:Spring创建CGLIB代理时,为了提升性能,会通过Objenesis工具跳过原类构造方法的执行来实例化代理对象。这导致代理对象自身的bars字段没有被初始化(原类构造里的bars = new ConcurrentHashMap<>()未执行),直接访问listener.bars时,拿到的是代理对象中未初始化的null字段,因此抛出NullPointerException。
  • getter方法的委托逻辑:调用getBars()方法时,由于该方法没有被@Async标注,代理对象会把方法调用委托给真正的Listener目标实例(这个实例的构造方法已正常执行,bars字段已初始化),所以能返回正确的ConcurrentHashMap实例,不会出现NPE。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 19:35:09