Spring-Bean生命周期-构造器访问Autowired字段为null

Spring Bean 生命周期:为什么构造器里访问 @Autowired 字段是 null

Spring 依赖注入的坑很多,其中一个经典问题是"构造器里访问 @Autowired 字段拿到 null"。本文讲清楚 Bean 生命周期的执行顺序,以及正确的注入方式。

一、问题案例

一个新写的服务,启动就报 NullPointerException。排查后发现,代码在构造器里直接使用了 @Autowired 注入的字段:

java 复制代码
@Service
public class OrderService {

    @Autowired
    private UserService userService;   // 字段注入

    public OrderService() {
        userService.init();            // ❌ 构造器里使用,这行必炸
    }
}

userService 是 null。明明标了 @Autowired,为什么是 null?

二、原理:Bean 生命周期顺序

Spring 创建 Bean 的顺序是固定的:

复制代码
1. 实例化(调用构造器)        ← 此时字段全是 null
2. 依赖注入(@Autowired)    ← 字段在这一步才被赋值
3. @PostConstruct            ← 初始化回调
4. 交给容器使用

构造器在第 1 步执行,依赖注入在第 2 步。所以构造器执行时,字段还没被注入,全是 null。字段注入的本质是"先 new 出来,再回头填字段",必然存在这个时间差。

三、正确写法

方案一:构造器注入(推荐)

java 复制代码
@Service
public class OrderService {

    private final UserService userService;

    public OrderService(UserService userService) {   // ✅ 依赖作为构造参数
        this.userService = userService;
        userService.init();                          // ✅ 构造器里已可用
    }
}

依赖作为构造参数传入,构造器里天然可用,字段还能声明为 final

方案二:把初始化逻辑挪到 @PostConstruct

java 复制代码
@Autowired
private UserService userService;

@PostConstruct
public void init() {
    userService.init();   // ✅ @PostConstruct 时字段已注入
}

四、延伸:三个初始化回调的顺序

如果需要在 Bean 初始化时执行逻辑,有三个入口,执行顺序如下:

顺序 方式 时机
1 @PostConstruct 字段注入完成后
2 InitializingBean.afterPropertiesSet() @PostConstruct 之后
3 @Bean(initMethod = "xxx") afterPropertiesSet 之后

三者都在依赖注入之后执行,都能安全访问字段。唯独构造器不行。

五、总结

  • 构造器执行时,@Autowired 字段尚未注入,访问必为 null。
  • 推荐使用构造器注入 ,或把初始化逻辑放到 @PostConstruct
  • 三个初始化回调(@PostConstruct / afterPropertiesSet / initMethod)都在注入之后。

我是无羡(小剑),全栈偏后端的独立开发者。

作品集:无羡 · 独立开发者作品集

如果对你有帮助,欢迎点赞、收藏、关注。

相关推荐
泡海椒35 分钟前
JQuick-Curl 拦截器实战:统一 Token、日志、请求预处理,让第三方接口调用真正工程化
后端
古法安卓36 分钟前
Android-重启流程源码解析
android·java·android studio
东方小月38 分钟前
一篇文章带你深入拆解Skill的本质与工程实现,让你不再滥用Skill
前端·人工智能·后端
清水白石0081 小时前
Python 类型设计深度解析:TypedDict 能否替代 dataclass?从 JSON 数据边界到 API 设计的最佳实践
java·python·json
晊晌_h1 小时前
嵌入式从0到精通——线程
java·开发语言·jvm
一木 之林1 小时前
五、C++ 新特性、关键字与编译原理(进阶)(二)
java·开发语言·c++
前端小张同学1 小时前
AI全栈开发最佳实践💐
前端·后端·架构
洋不写bug1 小时前
绕过权限检查,访问修改私有属性,反射,枚举,lambda
java·枚举·lambda·反射