在Spring整体框架的核心概念中,容器是核心思想,就是用来管理Bean的整个生命周期的,而在一个项目中,容器不一定只有一个,Spring中可以包括多个容器,而且容器有上下层关系,目前最常见的一种场景就是在一个项目中引入Spring和SpringMVC这两个框架,那么它其实就是两个容器,Spring是父容器,SpringMVC是其子容器,并且在Spring父容器中注册的Bean对于SpringMVC容器中是可见的,而在SpringMVC容器中注册的Bean对于Spring父容器中是不可见的,也就是子容器可以看见父容器中的注册的Bean,反之就不行。

springmvc 的配置文件和spring的配置文件都可以配置包扫描,如下:

<context:component-scan base-package="com.xxx"/>

从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 />

下面让我们来详细扒一扒Spring与SpringMVC的容器冲突的原因到底在那里?

  我们共有Spring和SpringMVC两个容器,它们的配置文件分别为applicationContext.xml和applicationContext-MVC.xml。

  1.在applicationContext.xml中配置了<context:component-scan base-package=“com.hafiz.www" />,负责所有需要注册的Bean的扫描和注册工作。

  2.在applicationContext-MVC.xml中配置<mvc:annotation-driven />,负责SpringMVC相关注解的使用。

  3.启动项目我们发现SpringMVC无法进行跳转,将log的日志打印级别设置为DEBUG进行调试,发现SpringMVC容器中的请求好像没有映射到具体controller中。

  4.在applicationContext-MVC.xml中配置<context:component-scan base-package=“com.hafiz.www" />,重启后,验证成功,springMVC跳转有效。

下面我们来查看具体原因,翻看源码,从SpringMVC的DispatcherServlet开始往下找,我们发现SpringMVC初始化时,会寻找SpringMVC容器中的所有使用了@Controller注解的Bean,来确定其是否是一个handler。1,2两步的配置使得当前springMVC容器中并没有注册带有@Controller注解的Bean,而是把所有带有@Controller注解的Bean都注册在Spring这个父容器中了,所以springMVC找不到处理器,不能进行跳转。

按照官方推荐根据不同的业务模块来划分不同容器中注册不同类型的Bean:Spring父容器负责所有其他非@Controller注解的Bean的注册,而SpringMVC只负责@Controller注解的Bean的注册,使得他们各负其责、明确边界。配置方式如下

  1.在applicationContext.xml中配置:

<!-- Spring容器中注册非@controller注解的Bean --><context:component-scan base-package="com.hafiz.www"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

  2.applicationContext-MVC.xml中配置

<!-- SpringMVC容器中只注册带有@controller注解的Bean --><context:component-scan base-package="com.hafiz.www" use-default-filters="false"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan> 

不要让两个扫描有重叠。原因有如下几点:

  1. 扫描的类增多, 项目启动时间会延长
  2. @PostConstruct 注解标注的方法会执行2次
  3. 会使事务失效

对于第三点会使事物失效,原因是什么? 
同时使用springmvc 和 spring, 那么项目中就会有两个容器。
spring的是父容器,先进行初始化; springmvc是子容器, 后进行初始化。子容器可以访问父容器的bean,父容器不能访问子容器的bean。 
springmvc后初始化,会重新创建service对象并重新注入,而springmvc再次创建service对象时不会读取spring的配置文件,因此也就无法知道service层是需要创建代理对象的,所以springmvc创建的service是普通的对象,而不是动态代理对象。

解决重叠扫描的方式

  • 方式1

即上面提到的 springmvc 只扫描controller的包, spring扫描其他组件。
springmvc 配置如下:

<context:component-scan base-package="com.xxx.**.cotroller"/> 

springmvc只会扫描com.xxx下任意目录或子目录下的controller包下的类

spring的配置如下:

<context:component-scan base-package="com.xxx.**.service.impl,com.xxx.**.dao"/>  

  • 方式2

用<context:include-filter/> 或 <context:exclude-filter/> 指定或排除某些类 
假设springmvc扫描如下:

<context:component-scan base-package="com.xxx.**.service.impl,com.xxx.**.dao"/> 

spring扫描如下:

<context:component-scan base-package="com.xxx"/>

那么就会重叠,springmvc会扫描service和dao,可以这样修改springmvc的配置:

<context:component-scan base-package="com.xxx">  <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>  <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context> 

用 <context:exclude-filter/> 排除了@Service 和 @Repository 两种注解标注的类,意思是告诉springmvc在扫描时,如果碰到这两个注解标注的类直接忽略,不要创建和注入对象。

方式1比方式2好,扫描的类更少,方式2仅仅是个例子,看起来有点画蛇添足。故意让springmvc扫描service和dao的包,又告诉他扫描时忽略service和dao,我仅仅是想引出还有<context:include-filter/> 和 <context:exclude-filter/>  这个配置. 有些特殊场景才用得上这个配置。

参考资料

http://www.cnblogs.com/hafiz/p/5875740.html

转载于:https://www.cnblogs.com/weixupeng/p/8540730.html

Spring和Spring MVC包扫描相关推荐

  1. Spring Boot多模块包扫描问题

    Spring Boot多模块包扫描问题 1.@SpringBootApplication @SpringBootApplication(scanBasePackages = "cn.mypa ...

  2. 【Spring】context:component-scan包扫描问题

    Spring 项目bean 无法注入或者初始化,可能是扫描问题,下面分两种情况研究 1.配置的bean 没有被扫描 先说一下<context:component-scan base-packag ...

  3. Spring注解详解包扫描bean注册

    一. @Configuration 配置 ​ 告诉Spring容器这是一个配置类 ==xml配置 二. @ComponentScan 包扫描 ​ 说明: //value:指定要扫描的包 //按照规则指 ...

  4. spring入门——如何实现包扫描

    如何实现包扫描 spring中的包扫描 如何实现呢? 自己实现 源码 验证 反思与总结 spring的实现 spring的源码 反思与总结 spring中的包扫描 在spring中有两种方式可以实现包 ...

  5. 解决在spring配置文件中包扫描无效问题

    自己写的一个小项目,用的框架ssm整合,里面明明配置了包扫描,但是就出现了这个异常 org.springframework.beans.factory.BeanCreationException: E ...

  6. java 扫描包框架_java – 在Android中实现类似Spring的包扫描

    我正在尝试为我正在开发的 Android框架实现类似于Spring的组件扫描的包扫描功能.基本上,我希望能够指定一个基本包,例如com.foo.bar并检索具有特定注释的所有Class实例.我不想用我 ...

  7. Spring 注解-包扫描

    4.包扫描 只要标注了@Controller.@Service.@Repository.@Component的,都会被扫描加入到容器里 **注意:**配置类自身也会被扫描到容器中,如果存在多个配置类, ...

  8. Spring Boot 原理解析—启动类包扫描原理

    为了何更好的理解该篇内容,请先阅读Spring Boot 原理解析-入口SpringApplication. 我们知道在使用Spring Boot时,Spring会自动加载Spring Boot中启动 ...

  9. 基于Spring包扫描工具和MybatisPlus逆向工程组件的数据表自动同步机制

    公司产品产出的项目较多.同步数据库表结构工作很麻烦.一个alter语句要跑到N个客户机上执行脚本.超级费时麻烦.介于此,原有方案是把增量脚本放到一resource包下,项目启动时执行逐行执行一次.但由 ...

最新文章

  1. rhel6ACL权限
  2. 3W法—what,why,how的运用
  3. Python PIL ImageDraw 和ImageFont模块学习
  4. Imagemagick常用指令
  5. Linux 多线程(一)线程概念:线程概念、线程与进程、线程间的独有与共享、多线程与多进程、线程控制
  6. 301. Remove Invalid Parentheses
  7. 用RtlAdjustPrivilege来调整进程权限(VB6.0代码)
  8. JavaScript数组合并
  9. Linux 学习作业:认识bash shell
  10. 网页设计Web尺寸规范
  11. filenet骗局_将FileNet P8与J2EE消息传递基础结构集成
  12. 量子统计中的涨落和时间关联函数的概念(谐振子例子)
  13. clouder manager卸载
  14. cdr多页面排版_cdr排版实例图文教程,教你CorelDRAW杂志内页排版方法
  15. Hexo | yilia主题安装
  16. 三点法求三维坐标精度误差评估实验
  17. 看《大话西游》,你哭了么
  18. 资产管理之RFID资产管理系统解决方案-RFID资产智能盘点-新导智能
  19. 微博2面:微信朋友圈是怎么实现的?
  20. PyQt5 QtChart-折线图

热门文章

  1. mybatis 大于小于转义_10 HTML5特性、转义字符和注释
  2. 四因素三水平正交试验表_机制砂中不同因素对混凝土性能影响研究
  3. php监听input,jQuery如何实时监听获取input输入框的值
  4. java高效编程_Java高效编程
  5. mysql 字符串有有乱码 转码_第09期:有关 MySQL 字符集的乱码问题
  6. linux记录用户命令的日志是,用日志记录Linux用户执行的每一条命令
  7. python默认数据类型转换_Python 数据类型转换
  8. 涂抹功能_贴片面膜、水洗面膜、涂抹面膜这三款怎么选?
  9. 代码和普通的java_Java中普通代码块,构造代码块,静态代码块区别及代码示例...
  10. 利用WiFi模块实现MicroPython远程开发