问题描述
初学spring,遇到些问题希望大家帮忙看看吧~contextConfigLocation和DispatcherServlet的分工主要是什么?百度了下,感觉DispatcherServlet的加载的applicationContext主要在springmvc的使用,可以定义controller,contextConfigLocation里的controller是无法访问到的。但实际尝试了下,发下web.xml如下配置可以访问到contextConfigLocation加载beans-servlet.xml里的controller<context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/project-servlet.xml,/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>
解决方案
本帖最后由 zjdl1234 于 2015-01-03 02:08:47 编辑
解决方案二:
项目引入SpringMVC后,实际上已经存在两个Spring容器:Spring父容器:1、管理业务层bean2、Web容器启动时会触发ServletContextListener事件,从而启动了Spring父容器,从Spring容器启动顺序看,它是首先被启动的3、它会扫描指定包名下面所有标注的类,并装配到容器,@Controller配置的bean也不例外。4、Web层可以通过WebApplicationContextUtils.getWebApplicationContext(servletContext)取得Spring父容器5、父容器不能访问子容器的beanSpringMVC子容器:1、管理Web层bean2、DispatcherServlet是标准的Servlet,它设置了加载顺序为2,则未访问的情况下就会被Web容器实例化并执行init()初始化方法,方法中启动了SpringMVC子容器,因此从顺序上说,它是在父容器之后启动的。3、它会扫描指定包名下面所有标注的类,并装配到容器,@Service等等配置的bean也不例外。4、它的父亲是上面的父容器,这一点要注意。5、可以通过WebApplicationContextUtils.getWebApplicationContext(servletContext,"org.springframework.web.servlet.FrameworkServlet.CONTEXT."+DispatcherServlet的servlet名)取得6、子容器可以访问父容器的bean因此,两个容器重复扫描时,会在两个容器里出现相同类型但不同实例的Bean(形象地说就内存地址不一样),即Controller会在两个容器中实例化,但是父容器里的基本用不着(千万不要做从下而上逆向调用的设计),原因是从web容器进入来的请求首先会被DispatcherServlet捕捉到,而DispatcherServlet会交给SpringMVC容器处理,也就是说从子容器取出bean来处理,当子容器没有对应的bean时,则会从父容器找。最后说下这种情况下的最佳实践:假如某项目包名规划如下:org.howsun.domain;org.howsun.dao;org.howsun.service;org.howsun.web;Spring父容器可以扫描到“org.howsun”,但是要排除掉@Controllerbean:<context:component-scanbase-package="org.howsun"><context:exclude-filtertype="annotation"expression="org.springframework.stereotype.Controller"/></context:component-scan>
SpringMVC子容器应该只扫描到“org.howsun.web”<context:component-scanbase-package="org.howsun.web"/>
解决方案三:
问题还是不明白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>
解决方案四:
经测试,似乎并不存在两个隔离的容器,只是配置文件不同而已。多个配置文件生成的bean都在同一容器中。在同一配置文件中不允许出现id相同的bean。在不同的配置文件中可以出现id相同的bean。但是,只要这些bean是singlton,那么从任何地方引用,得到的都是同一实例。
解决方案五:
不解,applicationContext中的确无法取得dispatchServlet中的bean
解决方案六:
引用4楼skyhitnow的回复:
不解,applicationContext中的确无法取得dispatchServlet中的bean
还没理解?父容器不能访问子容器的bean,反之则可以。补充一个问题:那么Controller类在父容器装配后,而不在子容器装配,为什么web层访问不到呢?因为SpringMVC子容器从一个URI到Method执行,要经过一序列HandlerExecutionChain,这是Spring父容器不具备的,DispatchServlet请求SpringMVC子容器来处理。
解决方案七:
之前说的都理解了,Web层去获取业务层的实例肯定是没问题的~但按上面的说法,我现在碰到的问题是:我在业务层的配置文件beans-servlet.xml里定义了Controller,居然直接访问到。(前提条件是在业务层、Web层中同时定义配置文件project-servlet.xml)beans-servlet.xml里的配置很简单,就是定义了一个点do的bean去实例了自定义的Controller类。