本帖最后由 zjdl1234 于 2015-01-03 02:08:47 编辑

解决方案 »

  1.   

    项目引入Spring MVC后,实际上已经存在两个Spring容器:Spring 父容器:
    1、管理业务层bean
    2、Web容器启动时会触发ServletContextListener事件,从而启动了Spring父容器,从Spring容器启动顺序看,它是首先被启动的
    3、它会扫描指定包名下面所有标注的类,并装配到容器,@Controller配置的bean也不例外。
    4、Web层可以通过WebApplicationContextUtils.getWebApplicationContext(servletContext)取得Spring父容器
    5、父容器不能访问子容器的beanSpring 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:<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”<context:component-scan base-package="org.howsun.web"/>
      

  2.   

    问题还是不明白
    Controller是在beans-servlet.xml里定义的,子容器里都没有关联应该是不会创建实例的
    父容器里加载了文件,但按你的说法是不实例化Controller的?那表示也不会访问到这个Controller啊,现在是可以访问到如果修改了父容器的配置,beans-servlet.xml里的Controller就访问不到了
    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/beans-servlet.xml</param-value>
    </context-param><listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener><servlet>
    <servlet-name>project</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>2</load-on-startup>
    </servlet> 
      

  3.   

    经测试,似乎并不存在两个隔离的容器,只是配置文件不同而已。
    多个配置文件生成的bean都在同一容器中。
    在同一配置文件中不允许出现id相同的bean。
    在不同的配置文件中可以出现id相同的bean。
    但是,只要这些bean是singlton,那么从任何地方引用,得到的都是同一实例。
      

  4.   

    不解,applicationContext中的确无法取得dispatchServlet中的bean
      

  5.   

    还没理解?父容器不能访问子容器的bean,反之则可以。补充一个问题:那么Controller类在父容器装配后,而不在子容器装配,为什么web层访问不到呢?
    因为Spring MVC子容器从一个URI到Method执行,要经过一序列HandlerExecutionChain,这是Spring父容器不具备的,DispatchServlet请求Spring MVC子容器来处理。
      

  6.   

    之前说的都理解了,Web层去获取业务层的实例肯定是没问题的~
    但按上面的说法,我现在碰到的问题是:
    我在业务层的配置文件beans-servlet.xml里定义了Controller,居然直接访问到。(前提条件是在业务层、Web层中同时定义配置文件project-servlet.xml
    beans-servlet.xml里的配置很简单,就是定义了一个点do的bean去实例了自定义的Controller类。