1 概念理解和知识铺垫
在 Spring 整体框架的核心概念中, 容器是核心思想, 就是用来管理 Bean 的整个生命周期的, 而在一个项目中, 容器不一定只有一个, Spring 中可以包括多个容器, 而且容器有上下层关系, 目前最常见的一种场景就是在一个项目中引入 Spring 和 SpringMVC 这两个框架, 那么它其实就是两个容器, Spring 是父容器, SpringMVC 是其子容器, 并且在父容器中注册的 Bean 对于子容器是可见的, 而在子容器中注册的 Bean 对于父容器是不可见的, 也就是子容器可以看见父容器中的注册的 Bean, 反之就不行
我们可以使用统一的如下注解配置来对 Bean 进行批量注册, 而不需要再给每个 Bean 单独使用 xml 的方式进行配置
<context:component-scan base-package="com.nnngu" />
从 Spring 提供的参考手册中我们得知该配置的功能是扫描配置的 base-package 包下的所有使用了 @Component 注解的类, 并且将它们自动注册到容器中, 同时也扫描 @Controller,@Service,@Respository 这三个注解, 因为他们是继承自 @Component
在项目中我们经常见到还有如下这个配置, 其实有了上面的配置, 这个是可以省略掉的, 因为上面的配置会默认打开以下配置以下配置会默认声明了 @Required@Autowired @PostConstruct@PersistenceContext@Resource@PreDestroy 等注解
<context:annotation-config/>
另外, 还有一个和 SpringMVC 相关如下配置, 经过验证, 这个是 SpringMVC 必须要配置的, 因为它声明了 @RequestMapping@RequestBody@ResponseBody 等并且, 该配置默认加载很多的参数绑定方法, 比如 json 转换解析器等
<mvc:annotation-driven />
2 使用场景分析
我们共有 Spring 和 SpringMVC 两个容器, 它们的配置文件分别为 applicationContext.xml 和 applicationContext-MVC.xml
在 applicationContext.xml 中配置了
<context:component-scan base-package=com.nnngu" />
, 负责所有需要注册的 Bean 的扫描和注册工作
在 applicationContext-MVC.xml 中配置
<mvc:annotation-driven />
, 负责 SpringMVC 相关注解的使用
启动项目我们发现 SpringMVC 无法进行跳转, 将 log 的日志打印级别设置为 DEBUG 进行调试, 发现 SpringMVC 容器中的请求好像没有映射到具体 controller 中
在 applicationContext-MVC.xml 中配置
<context:component-scan base-package=com.nnngu" />
, 重启后, 验证成功, springMVC 跳转有效
下面我们来查看具体原因, 翻看源码, 从 SpringMVC 的 DispatcherServlet 开始往下找, 我们发现 SpringMVC 初始化时, 会寻找 SpringMVC 容器中的所有使用了 @Controller 注解的 Bean, 来确定其是否是一个 handler1,2 两步的配置使得当前 springMVC 容器中并没有注册带有 @Controller 注解的 Bean, 而是把所有带有 @Controller 注解的 Bean 都注册在 Spring 这个父容器中了, 所以 springMVC 找不到处理器, 不能进行跳转
而在第 4 步配置中, SpringMVC 容器中也注册了所有带有 @Controller 注解的 Bean, 故 SpringMVC 能找到处理器进行处理, 从而正常跳转
3 官方推荐配置
在实际工程中会包括很多配置, 我们按照官方推荐根据不同的业务模块来划分不同容器中注册不同类型的 Bean:Spring 父容器负责所有其他非 @Controller 注解的 Bean 的注册, 而 SpringMVC 只负责 @Controller 注解的 Bean 的注册, 使得他们各负其责明确边界配置方式如下:
在 applicationContext.xml 中配置:
- <!-- Spring 容器中注册非 @Controller 注解的 Bean -->
- <context:component-scan base-package="com.nnngu">
- <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
- </context:component-scan>
applicationContext-MVC.xml 中配置
- <!-- SpringMVC 容器中只注册带有 @Controller 注解的 Bean -->
- <context:component-scan base-package="com.nnngu" use-default-filters="false">
- <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
- </context:component-scan>
4 总结
我们在清楚了 Spring 和 SpringMVC 的父子容器关系以及扫描注册的原理以后, 根据官方建议, 就可以很好把不同类型的 Bean 分配到不同的容器中进行管理出现 Bean 找不到或者 SpringMVC 不能跳转以及事务的配置失效的问题时, 我们就可以很快的定位以及解决问题了
来源: https://www.cnblogs.com/nnngu/p/8506812.html