Spring中@Controller与@Component的加载顺序及Autowired注入差异问题
一、@Controller与@Component的Bean实例化顺序差异
首先明确:@Controller本质是@Component的派生注解,它只是Spring MVC用来标识控制器类的特殊@Component,本身并没有改变Bean的加载(实例化、初始化)规则。
Spring中Bean的实例化顺序主要由以下因素决定,和注解本身(@Controller还是@Component)无关:
- 依赖关系:如果A Bean依赖B Bean,那么B会先于A实例化;
- @Order/@Priority注解:仅对
BeanPostProcessor、ApplicationListener这类特殊Bean的执行顺序生效,普通业务Bean的实例化顺序不受此注解直接影响; - 扫描顺序:
@ComponentScan指定的包扫描顺序,先扫描的包下的Bean会优先被处理; - 特殊组件的初始化逻辑:Spring MVC初始化时,会专门筛选所有@Controller标注的Bean来构建请求映射,但这是在Bean实例化之后的筛选动作,不是提前加载。
简单说:不存在@Controller一定比@Component先/后加载的固定规则,两者的Bean实例化顺序完全由Spring的Bean生命周期规则和项目配置决定。
二、静态成员变量注入失败的原因(和注解类型无关)
你遇到的问题核心不是@Component加载更早,而是Spring本身不支持直接对静态成员变量进行@Autowired注入——Spring的依赖注入是针对Bean实例的,静态变量属于类本身,不属于任何实例,Spring不会主动处理静态字段的注入。
为什么你觉得@Controller里注入成功?
大概率是你在@Controller里注入的是非静态成员变量,这类变量属于Bean实例,Spring会正常处理注入,所以不为null;如果在@Controller里直接@Autowired静态变量,同样会得到null。
为什么@Component里用@Autowired修饰setter方法能成功?
这里的setter方法应该是静态setter,示例代码如下:
@Component public class TestServer { private static TestService testService; @Autowired public static void setTestService(TestService testService) { TestServer.testService = testService; } }
这种情况下,Spring会识别到带有@Autowired的静态setter方法,在TestService实例化后调用这个静态方法,从而完成静态变量的赋值。这是Spring对静态字段的一种间接支持方式,和@Component的加载顺序无关——换成@Controller类这么写,同样可以生效。
总结:不管是@Controller还是@Component,直接@Autowired静态字段都会失败;通过静态setter+@Autowired实现静态变量赋值是Spring支持的间接方式,和Bean的加载顺序没有关系。
内容的提问来源于stack exchange,提问作者silver_coin

