@autowired注入为null的本质是对象未被spring容器管理或注入时机不当;需从“谁在用”(是否new创建)、“谁在管”(是否加注解且被扫描)、“什么时候用”(是否早于注入时序)三方面验证。

遇到 @Autowired 注入为 null,本质是对象没走 Spring 容器管理,或注入时机不对。排查要从“谁在用”“谁在管”“什么时候用”三个角度切入,不靠猜,靠验证。
看这个类是不是 Spring 管理的 Bean
Spring 只会对它创建和托管的对象执行依赖注入。如果类是手动 new 出来的(比如在拦截器、WebSocket 处理器、测试中直接 new XxxHandler()),那里面的 @Autowired 一定为 null —— 因为 Spring 根本没参与它的生命周期。
- 检查类上是否有
@Component、@Service、@Controller等注解,且包路径在@SpringBootApplication扫描范围内 - 如果是配置类(
@Configuration),避免在字段上直接@Autowired;应改用@Bean方法参数传入依赖(Spring 推荐方式) - 拦截器、WebSocket Handler、Security 的
AuthenticationSuccessHandler等框架回调类,切忌自己new,必须通过@Bean注册进容器
查依赖本身是否被 Spring 加载
注入目标(比如 UserService)如果压根没进容器,自然无法注入。
- 确认该类上有
@Service或@Repository等注解,且没有被@ConditionalOnMissingBean等条件排除 - 启动日志里搜
UserService或类名,看是否出现类似Creating shared instance of singleton bean 'userService' - 用
@PostConstruct打个断点或日志,验证该 Bean 是否真的初始化了(注意:此方法仅用于调试,不能替代正确定义生命周期)
盯紧字段初始化与注入的时序冲突
这是最隐蔽也最常被忽略的一类问题:字段在构造器执行前就初始化,而 @Autowired 要等构造完成才发生。
- 禁止在字段声明处调用未注入对象的方法,例如:
@Autowired private Rabbit rabbit;<br>private final String url = "https://..." + rabbit.getWallet(); // ❌ 启动就 NPE
- 正确做法是把逻辑移到
@PostConstruct方法里,或改用构造器注入(推荐):private final String url;<br>public MyService(Rabbit rabbit) { this.url = "..."+ rabbit.getWallet(); } - 抽象父类中定义
@Autowired字段时,子类虽是 Bean,但父类字段注入不稳定;建议改为构造器传参或子类自行注入
测试环境特别注意
单元测试或集成测试中注入失败,大概率是测试上下文没配对。
- JUnit 5 测试必须用
org.junit.jupiter.api.Test,别混用 JUnit 4 的org.junit.Test - 确保测试类加了
@SpringBootTest(集成测试)或@ContextConfiguration(手动加载配置) - 若用
@MockBean替代真实 Bean,记得它是覆盖而非补充,别漏掉关键依赖











