Spring和Spring MVC包扫描

摘要:
springmvc的配置文件和spring的配置文件都可以配置为包扫描,如下所示:从spring提供的参考手册中,我们知道该配置的功能是扫描配置的基本包包下使用@component注释的所有类,并自动将它们登记在容器中。同时,我们还扫描@Controller、@Service和@Repository注释,因为它们继承自@Component<context:annotation-config/>。此外,还有一个与SpringMVC相关的配置,如下所示。验证后,Spring MVC必须配置此配置,因为它声明了@RequestMapping、@RequestBody、@ResponseBody等。

在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

免责声明:文章转载自《Spring和Spring MVC包扫描》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇AMD Radeon HD 7650A显卡问题antd DatePicker框日期限制下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

springboot项目:扫描不到其他模块的包 Parameter 0 of constructor in com.zjxf.repository.UserRepository

报错信息如下: *************************** APPLICATION FAILED TO START *************************** Description: Parameter 0 of constructor in com.zjxf.repository.UserRepository req...

Bug实录 | 第二篇:重写WebMvcConfigurationSupport后SpringBoot自动配置失效

一、背景 公司的项目前段时间发版上线后,测试反馈用户的批量删除功能报错。正常情况下看起来应该是个小BUG,可怪就怪在上个版本正常,且此次发版未涉及用户功能的改动。因为这个看似小BUG我了解到不少未知的东西,在这里和你们分享下。 先声明下具体原因为了避免耽误找解决问题方法的小伙伴们的宝贵时间,因为项目重写了WebMvcConfigurationSupport...

SpringMvc流程

最近看《Spring源码深度理解》,看到了SpringMvc请求流程,记录下: 这张Spring流程图我借鉴了网上各位前辈的分析,加上自己的理解绘制的,如有侵权勿怪,如果各位觉得有帮助,也欢迎保存 :) 总结下我对SpringWebMvc流程:   Step1.请求被前端控制器DispatcherServlet接收;   Step2.前端控制器Dispa...

对象Bean与Map互转问题

一、摘要 在实际开发过程中,经常碰到需要进行对象与map之间互转的问题,其实对于对象、Map 之间进行互转有很多种方式,下面我们一起来梳理一下: 利用 JSON 工具包,将对象转成字符串,之后再转成 Map,这种需要转换2次,相对来说效率比较底; 利用 Java 反射,获取 Bean 类的属性和值,再转换到 Map 对应的键值对中,相对来说这种方法效率高...

使用java配置定时任务的几种配置方式及示例

Spring定时器,主要有两种实现方式,包括Java Timer定时和Quartz定时器! 1.Java Timer定时 首先继承java.util.TimerTask类实现run方法 package com.land; import java.util.Date;import java.util.TimerTask; public class Timer...

Spring声明式事务的配置~~~

/*2011年8月28日 10:03:30 by Rush  */ 环境配置 项目使用SSH架构,现在要添加Spring事务管理功能,针对当前环境,只需要添加Spring 2.0 AOP类库即可。添加方法: 点击项目右键->Build Path->Add librarys:  打开Add Libraries对话框,然后选定 MyEclipse...