SpringBoot 2.6.13中@Async Bean被@Autowired注入后myData字段为空问题
问题分析与解决:@Async导致@Autowired注入的Bean字段为空
问题场景
SpringBoot版本2.6.13,定义了标注
@Component、@Async的Data类,类里包含内部类MyData以及已初始化的myData字段。在实现CommandLineRunner的类中通过@Autowired注入Data后,发现myData字段为空;移除@Async注解后字段值恢复正常。已在入口类添加@EnableAsync,追踪到Bean被AsyncAnnotationBeanPostProcessor的postProcessAfterInitialization方法修改。
问题原因
- 当类标注
@Async时,Spring会通过AsyncAnnotationBeanPostProcessor为该类生成动态代理对象,你注入的其实是这个代理实例,而非原始的DataBean。 - 动态代理是在原始Bean初始化完成后创建的,如果你直接在字段上初始化
myData(比如private MyData myData = new MyData();),这个赋值只发生在原始实例里,代理实例的myData字段并不会被自动复制——代理只负责包装方法调用,不会继承原始实例的字段状态。 - 这就导致你拿到的代理对象里,
myData还是默认的null值。
解决方法(同时使用@Async与@Autowired)
方法1:用@PostConstruct初始化字段
把字段初始化逻辑放到@PostConstruct注解的方法中,Spring会在Bean创建(包括代理生成)的生命周期里执行这个方法,确保代理对象的字段也能被初始化:
@Component @Async public class Data { private MyData myData; @PostConstruct public void init() { myData = new MyData(); } public class MyData {} }
方法2:将内部类改为静态内部类
如果MyData不需要依赖外部Data实例的状态,改成静态内部类后,字段的直接初始化逻辑能被代理类正确识别和执行:
@Component @Async public class Data { private MyData myData = new MyData(); public static class MyData {} // 改为静态内部类 }
方法3:构造方法注入(适用于有依赖的场景)
如果MyData本身也是Spring管理的Bean,或者需要其他依赖,直接用构造方法注入,Spring会在生成代理前完成依赖注入和初始化,代理对象会继承这些已初始化的状态:
@Component @Async public class Data { private final MyData myData; // 构造方法注入,Spring自动处理初始化 public Data(MyData myData) { this.myData = myData; } // 建议将内部类改为静态 public static class MyData {} }
内容的提问来源于stack exchange,提问作者DC_pig
相关产品推荐
相关产品推荐

