Difference between applicationContext.xml and spring-servlet.xml in Spring Framework

Scenario 1

In client application (application is not web application, e.g may be swing app)

private static ApplicationContext context = new ClassPathXmlApplicationContext("test-client.xml");

context.getBean(name);
No need of web.xml. ApplicationContext as container for getting bean service. No need for web server container. In test-client.xml there can be Simple bean with no remoting, bean with remoting.

Conclusion: In Scenario 1 applicationContext and DispatcherServlet are not related.

Scenario 2

In a server application (application deployed in server e.g Tomcat). Accessed service via remoting from client program (e.g swing app)

Define listener in web.xml

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
At server startup ContextLoaderListener instantiates beans defined in applicationcontext.xml.

Assuming you have defined the following in applicationcontext.xml:

<import resource="test1.xml" />
<import resource="test2.xml" />
<import resource="test3.xml" />
<import resource="test4.xml" />
The beans are instantiated from all four configuration files test1.xml, test2.xml, test3.xml, test4.xml.

Conclusion: In Scenario 2 applicationContext and DispatcherServlet are not related.

Scenario 3

In a web application with spring MVC.

In web.xml define:

<servlet>
<servlet-name>springweb</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>springweb</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
When tomcat starts, beans defined in springweb-servlet.xml are instantiated. DispatcherServlet extends FrameworkServlet. In FrameworkServlet bean instantiation takes place for springweb . In our case springweb is FrameworkServlet.

Conclusion: In Scenario 3 applicationContext and DispatcherServlet are not related.

Scenario 4

In web application with spring MVC. springweb-servlet.xml for servlet and applicationcontext.xml for accessing the business service within the server program or for accessing DB service in another server program.

In web.xml the following are defined:

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
<servlet-name>springweb</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

</servlet>

<servlet-mapping>
<servlet-name>springweb</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
At server startup, ContextLoaderListener instantiates beans defined in applicationcontext.xml; assuming you have declared herein:

<import resource="test1.xml" />
<import resource="test2.xml" />
<import resource="test3.xml" />
<import resource="test4.xml" />
The beans are all instantiated from all four test1.xml, test2.xml, test3.xml, test4.xml. After the completion of bean instantiation defined in applicationcontext.xml then beans defined in springweb-servlet.xml are instantiated.

So instantiation order is root is application context, then FrameworkServlet.

Now it makes clear why they are important in which scenario.

<ref:http://stackoverflow.com/a/15941066>

 
 
 
Spring和SpringMVC作为Bean管理容器和MVC层的默认框架,已被众多WEB应用采用,而实际使用时,由于有了强大的注解功能,很多基于XML的配置方式已经被替代,但是在实际项目中,同时配置Spring和SpringMVC时会出现一些奇怪的异常,比如Bean被多次加载,多次实例化,或者依赖注入时,Bean不能被自动注入,但是明明你已经将该Bean注册了的。找原因还是要看问题的根源,我们从容器说起。
 
在Spring整体框架的核心概念中,容器是核心思想,就是用来管理Bean的整个生命周期的,而在一个项目中,容器不一定只有一个,Spring中可以包括多个容器,而且容器有上下层关系,目前最常见的一种场景就是在一个项目中引入Spring和SpringMVC这两个框架,其实就是2个容器,Spring是根容器,SpringMVC是其子容器,并且在Spring根容器中对于SpringMVC容器中的Bean是不可见的,而在SpringMVC容器中对于Spring根容器中的Bean是可见的,也就是子容器可以看见父容器中的注册的Bean,反之就不行。理解这点很重要,因为这是一个规则,是Spring自己设定的,但是往下看,我们会发现有些地方它并不默认使用这个规则。
 
当我们使用注解时,对于Bean注册这个功能的实现就不需要在给每个Bean配置XML了,只要使用统一的如下配置即可。
 
<context:component-scan base-package=“com.test" />
 
根据Spring提供的参考手册,该配置的功能是扫描默认包下的所有的@Component注解,并且自动注册到容器中,同时也扫描@Controller,@Service,@Respository这三个注解,他们是继承自@Component。
 
除了以上我们使用的扫描配置,在项目中我们经常见到的就是<context:annotation-config/>这个配置,其实有了以上的配置,这个是可以省略掉的。
还有一个SpringMVC相关的是<mvc:annotation-driven />配置,经过验证,这个是必须要配置的,因为它是和@RequestMapping结合使用的,这里补充下SpringMVC框架相关的知识点。
 

HandlerMapping,是SpringMVC中用来处理Request请求URL到具体Controller的,其自身也分成很多种类; 
HandlerAdapter,是SpringMVC中用来处理具体请求映射到具体方法的,其自身也分很多种类;

@RequestMapping这个注解的主要目的就是对具体的Controller和方法进行注册,以方便HandlerMapping用来处理请求的映射。但是@RequestMapping需要结合<mvc:annotation-driven />使用才能生效。

 
好了,有了以上基础知识的铺垫,我们看下现在这样的一个使用场景中,Spring与SpringMVC的容器冲突的原因在那里!
 
Spring配置文件applicationContext.xml,SpringMVC配置文件applicationContext-MVC.xml,这样项目中就有2个容器了,配置方式A,如下:
applicationContext.xml中配置了<context:component-scan base-package=“com.test" />,负责所有需要注册的Bean的扫描工作,applicationContext-MVC.xml中配置<mvc:annotation-driven />,负责springMVC相关注解的使用,启动项目发现,springMVC失效,无法进行跳转,开启log的DEBUG级别进行调试,发现springMVC容器中的请求好像没有映射到具体controller中;
 
配置方式B,如下:
为了快速验证效果,将<context:component-scan base-package=“com.test" />扫描配置到applicationContext-MVC.xml中,重启后,验证成功,springMVC跳转有效。
 
要想查看具体原因,翻看源码,从springMVC的DispatcherServlet开始看,在一个请求进来之后,发生了什么?漫长的查看之后,找到原因,如下。
 
springMVC初始化时,会寻找所有当前容器中的所有@Controller注解的Bean,来确定其是否是一个handler,而当前容器springMVC中注册的Bean中并没有@Controller注解的,注意,上面提及的配置方式A,所有的@Controller配置的Bean都注册在Spring这个父容器中了,看代码。
 
protected void initHandlerMethods() {
        if (logger.isDebugEnabled()) {
            logger.debug("Looking for request mappings in application context: " + getApplicationContext());
        }
        String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
                getApplicationContext().getBeanNamesForType(Object.class));
        for (String beanName : beanNames) {
            if (isHandler(getApplicationContext().getType(beanName))){
                detectHandlerMethods(beanName);
            }
        }
        handlerMethodsInitialized(getHandlerMethods());
    }
 
在方法isHandler中会判断当前bean的注解是否是controller,代码如下:
 
protected boolean isHandler(Class<?> beanType) {
        return AnnotationUtils.findAnnotation(beanType, Controller.class) != null;
    }
 
在配置方式B中,springMVC容器中包括了所有的@Controller注解的Bean,所以自然就能找到了。
以上是原因,解决办法是什么?注意看initHandlerMethods()方法中,detectHandlerMethodsInAncestorContexts这个Switch,它主要控制从那里获取容器中的bean,是否包括父容器,默认是不包括的。所以解决办法是有的,即在springMVC的配置文件中配置HandlerMapping的detectHandlerMethodsInAncestorContexts属性为true即可(这里需要根据具体项目看使用的是哪种HandlerMapping),让其检测父容器的bean。如下:
 
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
        <property name="detectHandlerMethodsInAncestorContexts">
            <value>true</value>
        </property>
    </bean>
 
以上已经有了2种解决方案了,但在实际工程中,会包括很多配置,根据不同的业务模块来划分,所以我们一般思路是各负其责,明确边界,Spring根容器负责所有其他非controller的Bean的注册,而SpringMVC只负责controller相关的Bean的注册。第三种方案如下:
 

Spring容器配置,排除所有@controller的Bean

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

SpringMVC容器配置,让其只包括@controller的Bean

<context:component-scan base-package="com.fsnip.open" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>
 
个人比较推荐第三种方案。引申一下,项目中使用事务的配置方案,也会在这种场景下失效,归根结底也是由于2个容器的可见性问题导致,可以结合具体问题按照上面的思路进行查找原因!(——全文完——)
 
<转:http://www.open-open.com/lib/view/open1452142677292.html>
 

Spring container vs SpringMVC container(webmvc container)的更多相关文章

  1. 【spring 国际化】springMVC、springboot国际化处理详解

    在web开发中我们常常会遇到国际化语言处理问题,那么如何来做到国际化呢? 你能get的知识点? 使用springgmvc与thymeleaf进行国际化处理. 使用springgmvc与jsp进行国际化 ...

  2. spring整合mybatis,springMVC的0配置文件方式

    0配置文件的形式主要是采用spring3.0提供的@configuration注解和spring容器在启动的时候会加载实现了WebApplicationInitializer的类,并调用其onStar ...

  3. Spring Data Jpa+SpringMVC+Jquery.pagination.js实现分页

    本博客介绍基于Spring Data这款orm框架加上Jquery.pagination插件实现的分页功能. 介绍一下Spring Data框架 spring Data : Spring 的一个子项目 ...

  4. spring容器和springmvc容器,以及web容器的关系

    说到spring和springmvc,其实有很多人分不清他们有什么区别,认为它俩是一样的,如果你问他项目里用的什么MVC技术,他会说我们用的spring和mybatis,或者spring和hibern ...

  5. 从源码层面聊聊面试问烂了的 Spring AOP与SpringMVC

    Spring AOP ,SpringMVC ,这两个应该是国内面试必问题,网上有很多答案,其实背背就可以.但今天笔者带大家一起深入浅出源码,看看他的原理.以期让印象更加深刻,面试的时候游刃有余. Sp ...

  6. 简述Spring容器与SpringMVC的容器的联系与区别

    简述Spring容器与SpringMVC的容器的联系与区别 2017年07月04日 10:55:07 阅读数:6260 摘要: 在Spring整体框架的核心概念中,容器的核心思想是管理Bean的整个生 ...

  7. Spring Boot实践——SpringMVC视图解析

    一.注解说明 在spring-boot+spring mvc 的项目中,有些时候我们需要自己配置一些项目的设置,就会涉及到这三个,那么,他们之间有什么关系呢? 首先,@EnableWebMvc=Web ...

  8. Spring容器与SpringMVC容器的区别与联系

    在spring整体框架的核心概念中,容器的核心思想是管理Bean的整个生命周期.但在一个项目中,Spring容器往往不止一个,最常见的场景就是在一个项目中引入Spring和SpringMVC这两个框架 ...

  9. 利用Intellij+MAVEN搭建Spring+Mybatis+MySql+SpringMVC项目详解

    http://blog.csdn.net/noaman_wgs/article/details/53893948 利用Intellij+MAVEN搭建Spring+Mybatis+MySql+Spri ...

  10. servlet容器,web容器,spring容器,springmvc容器的区别(转)

    web容器中有servlet容器,spring项目部署后存在spring容器和springmvc容器.其中spring控制service层和dao层的bean对象.springmvc容器控制contr ...

随机推荐

  1. 安卓使用pull解析器解析XML文件

    学习一下: public class MainActivity extends Activity { List<City> cityList; @Override protected vo ...

  2. centos7.0 64位系统 安装PHP 支持 nginx

    1  安装PHP所需要的扩展 yum -y install libxml2 libxml2-devel openssl openssl-devel bzip2 bzip2-devel curl cur ...

  3. JavaWeb chapter9 JSP基础

    1.  Servlet的缺陷 一个动态网页中,大部分内容都是HTML代码等固定不变的内容,编写和修改HTML非常不方便,令人厌恶: 部署Servlet是繁琐而且容易出错的任务:(Servlet3.0规 ...

  4. ionic 安装本地插件极光推送

    问题:按照官方文档的步骤 假如把插件保存到了D:\push\jpush,当执行到 cordova plugin add D:\push\jpush 的时候,ionic 不是从本地目录安装,而是从reg ...

  5. 快消零售行业怎么用K2做开关店管理?

    提起迪卡侬,想到的便是它汇聚所有运动于同一个屋檐下的盛况.从来没有一家体育用品零售店可以像迪卡侬一样,涵盖几乎所有级别的运动产品.从入门级到最专业的运动产品,应有尽有,不仅产品质量有保证,价格也平易近 ...

  6. OC基础--Hello Shit

    /*  Foundation.h为主头文件, 主头文件中又拷贝了该工具箱中所有工具的头文件, 我们只需要导入主头文件就可以使用该工具箱中所有的工具, 避免了每次使用都要导入一个对应的头文件  工具箱的 ...

  7. CodeForces 688A-Opponents

    题意: Arya在学校有n个敌人(一串含有0,1的数字表示),有一个游戏规则,如果当天这n个敌人全部出席("1"代表出席,),即这串数字全部为"1",则Arya ...

  8. Android SurfaceView

    今天介绍一下SurfaceView的用法,SurfaceView一般与SurfaceHolder结合使用,SurfaceHolder用于向与之关联的SurfaceView上绘图,调用SurfaceVi ...

  9. Jmeter—7 测试中使用到的定时器和逻辑控制器

    1 测试中提交数据有延时1min,所以查询数据是否提交成功要设置定时器. 固定定时器页面:单位是毫秒 [dinghanhua] 2 集合点.Synchronizing Timer 集合点编辑:集合用户 ...

  10. 使用本地JConsole监控远程JVM (转)

    问题背景   Tomcat经常崩溃crash,想看看JVM内存使用情况,就想到了用Jconsole监控,以前只是监控本地的JVM,这次要监控远程的,遇到了不少问题.   经过几个小时的努力,参考了众多 ...