文档章节

spring父子容器

OSC_Mgxcbo
 OSC_Mgxcbo
发布于 2017/08/25 11:39
字数 1483
阅读 13
收藏 2
Spring 和SpringMVC 的父子容器关系 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了,只要使用统一的如下配置即可。 1 根据Spring提供的参考手册,该配置的功能是扫描默认包下的所有的@Component注解,并且自动注册到容器中,同时也扫描 @Controller@Service,@Respository这三个注解,他们是继承自@Component。 除了以上我们使用的扫描配置,在项目中我们经常见到的就是这个配置,其实有了以上的配置,这个是可以省略掉的。 还有一个SpringMVC相关的是配置,经过验证,这个是必须要配置的,因为它是和@RequestMapping结合使用的,这里补充下SpringMVC框架相关的知识点。 HandlerMapping,是SpringMVC中用来处理Request请求URL到具体Controller的,其自身也分成很多种类; HandlerAdapter,是SpringMVC中用来处理具体请求映射到具体方法的,其自身也分很多种类; @RequestMapping这个注解的主要目的就是对具体的Controller和方法进行注册,以方便HandlerMapping用来处理请求的映射。但是@RequestMapping需要结合使用才能生效。 好了,有了以上基础知识的铺垫,我们看下现在这样的一个使用场景中,Spring与SpringMVC的容器冲突的原因在那里! Spring配置文件applicationContext.xml,SpringMVC配置文件applicationContext-MVC.xml,这样项目中就有2个容器了,配置方式A,如下: applicationContext.xml中配置了,负责所有需要注册的Bean的扫描工作,applicationContext-MVC.xml中配置,负责springMVC相关注解的使用,启动项目发现,springMVC失效,无法进行跳转,开启log的DEBUG级别进行调试,发现springMVC容器中的请求好像没有映射到具体controller中; 配置方式B,如下: 为了快速验证效果,将扫描配置到applicationContext-MVC.xml中,重启后,验证成功,springMVC跳转有效。 要想查看具体原因,翻看源码,从springMVC的DispatcherServlet开始看,在一个请求进来之后,发生了什么?漫长的查看之后,找到原因,如下。 springMVC初始化时,会寻找所有当前容器中的所有@Controller注解的Bean,来确定其是否是一个handler,而当前容器springMVC中注册的Bean中并没有@Controller注解的,注意,上面提及的配置方式A,所有的@Controller配置的Bean都注册在Spring这个父容器中了,看代码。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 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,代码如下: 1 2 3 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。如下: 1 2 3 4 5 true 以上已经有了2种解决方案了,但在实际工程中,会包括很多配置,根据不同的业务模块来划分,所以我们一般思路是各负其责,明确边界,Spring根容器负责所有其他非controller的Bean的注册,而SpringMVC只负责controller相关的Bean的注册。第三种方案如下: Spring容器配置,排除所有@controller的Bean 1 2 3 SpringMVC容器配置,让其只包括@controller的Bean 1 2 3 个人比较推荐第三种方案。引申一下,项目中使用事务的配置方案,也会在这种场景下失效,归根结底也是由于2个容器的可见性问题导致,可以结合具体问题按照上面的思路进行查找原因! 引用一下海涛的博客中的一张图。 原图地址http://jinnianshilongnian.iteye.com/blog/1602617 转载开涛博客

本文转载自:http://www.cnblogs.com/zyzcj/p/5286190.html

上一篇: springMVC
下一篇: zookeeper
OSC_Mgxcbo
粉丝 3
博文 40
码字总数 6598
作品 0
私信 提问
spring的父子上下文容器及配置

本文由作者张远道授权网易云社区发布。 spring父子容器 spring总的上下文容器有父子之分。父容器和子容器。父容器对子容器可见,子容器对父容器不可见。 对于传统的spring mvc来说,spring ...

网易云
2018/12/11
0
0
Spring 容器(Spring 的上下文)

最近在做项目时牵扯到有关父子上下文的概念。 何为父子上下文呢? 父上下文: 使用listener监听器来加载配置文件,如下: Spring 会创建一个WebApplicationContext上下文,称为父上下文(父容...

666B
2014/06/22
0
3
SpringMVC+Spring事物失效问题

1、spring扫描配置 springmvc扫描配置导致事物失效 一个项目中既有SpringMVC又有Spring 的时候,会发生事物失效问题 原因:使用的spring注解+springMVC注解,默认情况下spring应该先加载appli...

宿小帅
2016/10/12
50
0
spring容器和springmvc容器,以及web容器的关系

首先 springmvc和spring它俩都是容器,容易就是管理对象的地方,例如Tomcat,就是管理servlet对象的,而springMVC容器和spring容器,就是管理bean对象的地方,再说的直白点,springmvc就是管...

少年已不再年少
03/25
0
0
项目中SpringMVC、Spring和Struts的区别讲解

导读:近期做到的项目中,用到的框架师SSM(SpringMVC+Spring+Mybatis),那么在这之前用过SSH,这里主要是区分一下SpringMVC和Struts,但是由于SpringMVC和Spring真的也挺容易迷糊的,所以,...

yiguang_820的博客
2017/12/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

分布式架构 实现分布式锁的常见方式

一、我们为什么需要分布式锁? 在单机时代,虽然不需要分布式锁,但也面临过类似的问题,只不过在单机的情况下,如果有多个线程要同时访问某个共享资源的时候,我们可以采用线程间加锁的机制...

太猪-YJ
50分钟前
3
0
GitLab Docker 安装记录

安装环境 环境Centos7.4 64 1.拉取镜像文件 docker pull gitlab/gitlab-ce:latest 2.docker 安装 git.zddts.com 为访问域名或换成可以访问的IP docker run -d --hostname git.***.com -p ......

侠者圣
今天
0
0
部署kubernates dashboard

参考官方文档: https://github.com/kubernetes/dashboard 直接部署官方默认的dashboard: kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/deploy/r......

猫海豚
今天
0
0
Docker中Redis的安装

一、下载镜像 docker pull redis 二、创建外挂目录及配置 mkdir /opt/docker/redismkdir /opt/docker/redis/confmkdir /opt/docker/redis/data 三、安装 docker run -d --name compose_r......

闊苡訆涐囍醣
今天
0
0
JNI内存泄露处理方法汇总

在c++中new的对象,如果不返回java,必须用release掉,否则内存泄露。包括NewStringUTF,NewObject。如果返回java不必release,java会自己回收。   jstring jstr = env->NewStringUTF((*p)....

shzwork
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部