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

Spring Boot中@Autowired注入依赖的内部成员为null问题咨询

问题根本原因

  1. 你的代码中存在两类BeanTest实例:
    • 第一类是你在TimeOutConfig的@Bean方法中手动new BeanTest(value1, value2)生成的实例,该实例调用带参构造,执行了beanWebClient()方法,内部b1属性有值,你通过构造方法将该实例传给了手动创建的User对象。
    • 第二类是Spring扫描到BeanTest类上的@Component注解后,自动调用无参构造生成的全局单例BeanTest实例,该实例的v1、v2为默认值0,也没有执行beanWebClient()方法,内部b1属性为null。
  2. 当你在User类的beanTest字段上加了@Autowired注解后,Spring会对所有纳入容器管理的User实例(包括你在配置类中通过@Bean注册的两个User实例)执行字段注入逻辑:Spring会将自己管理的全局单例、无参构造生成的BeanTest实例注入到beanTest字段,直接覆盖了你之前通过构造方法手动赋值的带参数BeanTest实例。
  3. 此时User中的beanTest实际是Spring生成的无参BeanTest,内部b1为null,调用message()方法访问b1时就会抛出空指针异常。
  4. 当你去掉@Autowired注解后,Spring不会对beanTest字段执行注入覆盖,保留了你手动赋值的带参数BeanTest实例,因此运行正常。

正确实现方案

你的需求是每个User实例绑定对应自定义参数的BeanTest,不需要依赖Spring全局注入BeanTest,可选两种优化方案:

方案1:移除User的@Component注解,完全通过@Bean注册实例

你已经在配置类中手动注册了两个User的@Bean,不需要再给User类加@Component注解,额外加的@Component会生成无用的全局User单例,还容易引发注入混淆。此时可以保留字段不加@Autowired,完全通过构造方法赋值即可,也就是你当前正常运行的写法:

// 移除@Component注解
public class User {
    private final BeanTest beanTest;

    public User(BeanTest beanTest){
        this.beanTest = beanTest;
    }

    public void message() {
        beanTest.message();
    }
}

方案2:将自定义的BeanTest也注册为Spring Bean

如果你需要让Spring自动注入BeanTest,可以把每个自定义参数的BeanTest也注册为Spring容器中的Bean,再和对应的User绑定:

@Configuration
public class TimeOutConfig {
    @Value("${value1}")
    private int value1;
    @Value("${value2}")
    private int value2;
    @Value("${value3}")
    private int value3;
    @Value("${value4}")
    private int value4;

    @Bean
    BeanTest boBeanTest() {
        return new BeanTest(value1, value2);
    }

    @Bean
    User boTimeOut(@Qualifier("boBeanTest") BeanTest boBeanTest) {
        System.out.println("In BOTimeOutConfig");
        return new User(boBeanTest);
    }

    @Bean
    BeanTest bseBeanTest() {
        return new BeanTest(value3, value4);
    }

    @Bean(name = "BSETimeout")
    User getBSEUser(@Qualifier("bseBeanTest") BeanTest bseBeanTest) {
        System.out.println("In BSETimeOutConfig");
        return new User(bseBeanTest);
    }
}

这种场景下也推荐使用构造方法注入代替字段注入,Spring 4.3+之后如果类只有一个构造方法,会自动注入构造方法的参数,不需要额外加@Autowired注解。

额外优化建议

  • 不要同时给类加@Component又在配置类中注册@Bean,会导致容器中存在多个同类型实例,容易引发注入混淆
  • 手动new出来的对象默认不归Spring管理,不会执行自动注入、AOP等逻辑,尽量把需要Spring管理的对象都通过@Bean或者@Component注册到容器
  • 优先使用构造方法注入代替字段注入,代码更健壮,方便单元测试,也不会出现注入覆盖的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 02:15:03