sping项目中ContextConfigLocation中指定文件位置的设置规则

如果没有接触过公司项目的小白或者刚入职不久的菜鸟,可能一直认为在web.xml中配置spring肯定是如下图这样的,/WEB-INF/classes/applicationContext.xml

这里写图片描述

但是实际中呢,一般公司是不会把dao和service直接以bean的方式放入application.xml中的,而是分别为dao和service弄一个新的配置文件,一般是以dao.xml和service.xml形式的名字弄一个配置文件,之后,再在web.xml中配置param-value,具体如下图

这里写图片描述

采用通配符进行匹配。在公司中,肯定不可能像练习那样,所有东西都放到一起,可能自己认为,放到一起更方便看和管理,但是一个真正的公司项目是很大的,由多人分工,因此模块化,更易于管理和分配(刚好我们公司就采用如此配置,导致我有些疑惑,进而查证一番,拼凑了这个帖子以供大家参考)。

采用上述配置时,如果设置不当,则会引起双重加载controller层的bean类,如下图所示,是通用的设置SpringMvc上下文的方式,

<servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 可以自定义servlet.xml配置文件的位置和名称,默认为WEB-INF目录下,名称为[<servlet-name>]-servlet.xml,如spring-servlet.xml
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring-servlet.xml</param-value>&nbsp; 默认
    </init-param>
    -->
    <load-on-startup>1</load-on-startup>
</servlet>

这样的话,当web.xml中的ContextConfigLocation采用上述的通配符方式设置文件加载位置的话,就会产生重复加载,虽然不至于出问题,但是其实并不是很妥当,至于原因,如下所述:

项目引入Spring MVC后,实际上已经存在两个Spring容器:

Spring 父容器:
1、管理业务层bean
2、Web容器启动时会触发ServletContextListener事件,从而启动了Spring父容器,从Spring容器启动顺序看,它是首先被启动的
3、它会扫描指定包名下面所有标注的类,并装配到容器,@Controller配置的bean也不例外。
4、Web层可以通过WebApplicationContextUtils.getWebApplicationContext(servletContext)取得Spring父容器
5、父容器不能访问子容器的bean

Spring MVC子容器:
1、管理Web层bean
2、DispatcherServlet是标准的Servlet,它设置了加载顺序为2,则未访问的情况下就会被Web容器实例化并执行init()初始化方法,方法中启动了Spring MVC子容器,因此从顺序上说,它是在父容器之后启动的。
3、它会扫描指定包名下面所有标注的类,并装配到容器,@Service等等配置的bean也不例外。
4、它的父亲是上面的父容器,这一点要注意。
5、可以通过WebApplicationContextUtils.getWebApplicationContext(servletContext,”org.springframework.web.servlet.FrameworkServlet.CONTEXT.” + DispatcherServlet的servlet名)取得
6、子容器可以访问父容器的bean

因此,两个容器重复扫描时,会在两个容器里出现相同类型但不同实例的Bean(形象地说就内存地址不一样),即Controller会在两个容器中实例化,但是父容器里的基本用不着(千万不要做从下而上逆向调用的设计),原因是从web容器进入来的请求首先会被DispatcherServlet捕捉到,而DispatcherServlet会交给Spring MVC容器处理,也就是说从子容器取出bean来处理,当子容器没有对应的bean时,则会从父容器找。

最后说下这种情况下的最佳实践:
假如某项目包名规划如下:
org.howsun.domain;
org.howsun.dao;
org.howsun.service;
org.howsun.web;

Spring父容器可以扫描到“org.howsun”,但是要排除掉@Controller bean:
XML/HTML code

<context:component-scan base-package="org.howsun">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

Spring MVC 子容器应该只扫描到“org.howsun.web”
XML/HTML code

<context:component-scan base-package="org.howsun.web"/>

以上解释引用@howsun_zh的,出处https://bbs.csdn.net/topics/390964299,我觉得回答的很贴切,就拿过来了,也解释了我心中的疑惑。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值