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

为何Spring单例Bean在字段与方法参数@Autowire时实例不同?

问题描述

调用GET /test接口(对应方法BeanScopeTestController#checkTheSameInstance)时,输出结果为method equals: false; instance equals: false,这是为何?

Spring中@Bean的默认作用域是Singleton,原本期望类字段singletonBean1和方法参数singletonBean2从Spring容器中获取同一个实例,但实际注入的是SingletonBean的不同实例。是Spring MVC中方法参数上的@Autowire工作机制不同导致作用域被覆盖,还是另有原因?

预期是字段和方法参数注入的是同一个SingletonBean实例。

相关代码

BeanScopeTestController.java

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
@Slf4j
class BeanScopeTestController {

    private final SingletonBean singletonBean1;

    @Autowired
    BeanScopeTestController(SingletonBean singletonBean) {
        this.singletonBean1 = singletonBean;
    }
    
    @GetMapping
    String checkTheSameInstance(@Autowired SingletonBean singletonBean2) {
        log.info(singletonBean1.toString());
        log.info(singletonBean2.toString());
        boolean methodEquals = singletonBean1.equals(singletonBean2);
        boolean instanceEquals = singletonBean1 == singletonBean2;
        return String.format("method equals: %s; instance equals: %s", methodEquals, instanceEquals);
    }

}

SingletonBean.java

import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@ToString
@EqualsAndHashCode
class SingletonBean {

    private static int idProvider = 0;
    private final int id;

    public SingletonBean() {
        this.id = idProvider++;
    }
    
}

SpringDemoApplication.java

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringDemoApplication.class, args);
    }

}
问题原因

核心问题在于Bean类的访问修饰符:

  • SingletonBean和BeanScopeTestController都使用了默认的包访问权限(未添加public修饰符)。
  • Spring的组件扫描机制默认只会识别并托管public修饰的类作为Bean。对于非public的类,即使添加了@Component或@RestController注解,Spring容器无法将其纳入单例管理逻辑,每次注入时都会通过反射创建一个新的实例。
  • 这和Spring MVC中方法参数的@Autowired机制无关,本质是目标Bean没有被Spring容器正确管理为单例。
解决方法

给SingletonBean和BeanScopeTestController添加public修饰符,让Spring组件扫描能正确识别并将它们作为单例Bean存入容器:

修改后的SingletonBean.java:

import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@ToString
@EqualsAndHashCode
public class SingletonBean { // 添加public修饰符

    private static int idProvider = 0;
    private final int id;

    public SingletonBean() {
        this.id = idProvider++;
    }
    
}

修改后的BeanScopeTestController.java:

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
@Slf4j
public class BeanScopeTestController { // 添加public修饰符

    private final SingletonBean singletonBean1;

    @Autowired
    BeanScopeTestController(SingletonBean singletonBean) {
        this.singletonBean1 = singletonBean;
    }
    
    @GetMapping
    String checkTheSameInstance(@Autowired SingletonBean singletonBean2) {
        log.info(singletonBean1.toString());
        log.info(singletonBean2.toString());
        boolean methodEquals = singletonBean1.equals(singletonBean2);
        boolean instanceEquals = singletonBean1 == singletonBean2;
        return String.format("method equals: %s; instance equals: %s", methodEquals, instanceEquals);
    }

}

修改后再次调用接口,会得到预期结果:method equals: true; instance equals: true。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 06:33:23