为何@ComponentScan在Spring不同配置类中生效情况存在差异?
@ComponentScan在Spring不同配置类中生效差异的原因
这个问题的核心是Spring MVC默认的双层上下文父子隔离机制,具体逻辑如下:
1. Spring Web的上下文分层规则
项目启动时会初始化两个层级独立的ApplicationContext,为父子关系,职责完全隔离:
- 父上下文(根上下文):由
getRootConfigClasses()返回的配置类(你的项目中为RootConfig)加载,通常用来注册服务层、DAO层、事务管理器等全局通用的非Web Bean。父上下文的Bean对所有子上下文可见,但父上下文无法访问子上下文的Bean。 - 子上下文(Servlet上下文):由
getServletConfigClasses()返回的配置类(你的项目中为ServletConfig)加载,是DispatcherServlet专属的上下文,仅用来注册Controller、视图解析器、资源处理器等Web相关组件。
2. 配置生效差异的核心原因
DispatcherServlet处理请求时,只会从自己所属的子上下文中查找请求对应的Controller和映射规则,不会主动扫描父上下文的Bean:
- 把
@ComponentScan(basePackages = {"org.zerock.controller"})放在ServletConfig上时,扫描到的Controller会直接注册到DispatcherServlet的子上下文,请求可以正常匹配到处理方法,配置正常生效。 - 把这个扫描注解放在
RootConfig上时,Controller会被注册到父上下文,DispatcherServlet找不到父上下文里的Controller实例,自然无法建立请求URI和处理方法的映射,配置无法生效。
3. 常规开发最佳实践
实际项目中通常会拆分组件扫描的范围,避免Bean重复注册:
RootConfig的@ComponentScan仅扫描service、mapper、common等非Web包路径ServletConfig的@ComponentScan仅扫描controller包路径
内容的提问来源于stack exchange,提问作者jisoo choi
相关产品推荐
相关产品推荐

