菜单

Spring和SpringMVC父子容器关系初窥

2018年11月18日 - jQuery

其三、具体状况分析

  下面为咱们来详细扒一卧Spring与SpringMVC的器皿冲突的由到底以那边?

  我们共有Spring和SpringMVC两单容器,它们的布局文件分别吗applicationContext.xml和applicationContext-MVC.xml。

  1.当applicationContext.xml中配备了<context:component-scan base-package=“com.hafiz.www”
/>,负责所有需要报之Bean的扫描和报工作。

  2.每当applicationContext-MVC.xml中布局<mvc:annotation-driven />,负责SpringMVC相关注解的应用。

  3.开行项目我们发现SpringMVC无法进行跳转,将log的日志打印级别设置也DEBUG进行调剂,发现SpringMVC容器中之呼吁好像从没映射到具体controller中。

  4.每当applicationContext-MVC.xml中安排<context:component-scan base-package=“com.hafiz.www”
/>,重开后,验证成功,springMVC跳反中。

  下面我们来查阅具体由,翻看源码,从SpringMVC的DispatcherServlet开始往生搜寻,我们发现SpringMVC初始化时,会寻找SpringMVC容器中之兼具以了@Controller注解的Bean,来规定其是否是一个handler。1,2片步的布置使得当前springMVC容器中并无注册带有@Controller注解的Bean,而是把所有带有@Controller注解的Bean都注册于Spring这个父容器中了,所以springMVC找不至电脑,不能够开展跳转。核心源码如下:

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;
}

如果当第4步配置中,SpringMVC容器中也注册了装有带有@Controller注解的Bean,故SpringMVC能找到电脑进行拍卖,从而正常跳转。

咱们找到了产出无可知对跳转的原委,那么她的解决办法是啊为?

  我们注意到以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>

不过于实质上工程被见面席卷多配备,我们按官方推荐根据不同的事体模块来划分不同容器中注册不同档次的Bean:Spring父容器负责所有其他非@Controller注解的Bean的注册,而SpringMVC只承担@Controller注解的Bean的报,使得他们承担、明确边界。配置方式如下

  1.在applicationContext.xml中配置:

<!-- Spring容器中注册非@controller注解的Bean -->
<context:component-scan base-package="com.hafiz.www">
   <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

  2.applicationContext-MVC.xml中配置

<!-- SpringMVC容器中只注册带有@controller注解的Bean -->
<context:component-scan base-package="com.hafiz.www" use-default-filters="false">
   <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>

有关use-default-filters=”false”的意向,请参见另一样首博客:context:component-scan标签的use-default-filters属性的意和原理分析

其三、具体状况分析

第二、概念理解与学识铺垫

  于Spring整体框架的为主概念中,容器是核心思想,就是之所以来保管Bean的浑生命周期的,而在一个类别遭到,容器不肯定只有一个,Spring中好包括多个容器,而且容器有上下层关系,目前极度广泛的平种植现象就是是于一个色面临引入Spring和SpringMVC这简单个框架,那么它们事实上就算是鲜单容器,Spring是父容器,SpringMVC是其子容器,并且于Spring父容器中登记的Bean对于SpringMVC容器中凡是可见的,而以SpringMVC容器中登记的Bean对于Spring父容器中是不可见的,也便是子容器可以看见父容器中之挂号之Bean,反的便非常。

  我们可下统一的如下注解配置来对Bean进行批量注册,而非需要再行叫每个Bean单独使用xml的法展开布置。

<context:component-scan base-package="com.hafiz.www" />

  从Spring提供的参考手册中我们意识到该配置的成效是扫描配置的base-package包下的富有应用了@Component注解的类似,并且以她活动注册到容器被,同时也扫描@Controller,@Service,@Respository这三单注解,因为她们是继往开来自@Component。

  以档次遭到我们经常看看还有如下是布局,其实生矣地方的配备,这个是足以看略掉的,因为地方的安排会默认打开以下配置。以下配置会默认声明了@Required、@Autowired、
@PostConstruct、@PersistenceContext、@Resource、@PreDestroy等注解。

<context:annotation-config/>

  另外,还有一个及SpringMVC相关如下配置,经过验证,这个是SpringMVC必须使部署的,因为其声明了@RequestMapping、@RequestBody、@ResponseBody等。并且,该配置默认加载很多底参数绑定方法,比如json转换解析器等。

<mvc:annotation-driven />

如果面就词配置spring3.1之前的版及以下配置方式相当

<!--配置注解控制器映射器,它是SpringMVC中用来将Request请求URL到映射到具体Controller-->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<!--配置注解控制器映射器,它是SpringMVC中用来将具体请求映射到具体方法-->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>

spring3.1之后的本子与以下配置方式相当

<!--配置注解控制器映射器,它是SpringMVC中用来将Request请求URL到映射到具体Controller-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!--配置注解控制器映射器,它是SpringMVC中用来将具体请求映射到具体方法-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<context:annotation-config/>

一、背景

  最近出于品种的保管扫描出现了问题,在化解问题的过程遭到,偶然发现了Spring和SpringMVC是生父子容器关系的,而且正是为是才往往会出现包扫描的题目,我们于这个来分析及掌握Spring和SpringMVC的父子容器关系而于来Spring和SpringMVC配置文件被保证扫描的官推荐方式。

脚被咱们来详细扒一卧Spring与SpringMVC的器皿冲突的因到底以那边?

三、总结

  这样我们在知道了spring和springMVC的父子容器关系、以及扫描注册的法则以后,根据官方建议我们不怕可死好把不同门类的Bean分配到不同之器皿被开展管制。再起Bean找不交要SpringMVC不可知跳反和工作的部署失效的题目,我们就算可高速的一定及解决问题了。很开心,有木有~

 

1.在applicationContext.xml中配置:

  我们好行使统一的如下注解配置来针对Bean进行批量登记,而不待重被每个Bean单独使用xml的措施进行配置。

以术isHandler中会判断时bean的笺注是否是controller,源码如下:

若果面就词配置spring3.1之前的本及以下配置方式相当

  下面我们来查看具体原因,翻看源码,从SpringMVC的DispatcherServlet开始通往生搜寻,我们发现SpringMVC初始化时,会招来SpringMVC容器中之持有以了@Controller注解的Bean,来规定那个是否是一个handler。1,2点滴步之布使得当前springMVC容器中连从未挂号带有@Controller注解的Bean,而是将富有带有@Controller注解的Bean都注册在Spring这个父容器中了,所以springMVC找不至计算机,不能够展开跳转。核心源码如下:

3.起步项目我们发现SpringMVC无法进行跳转,将log的日志打印级别设置也DEBUG进行调试,发现SpringMVC容器中的伸手好像没映射到现实controller中。

  于路面临我们常看看还有如下是布局,其实产生了上面的布局,这个是足以看看略掉的,因为上面的配置会默认打开以下配置。以下配置会默认声明了@Required、@Autowired、
@PostConstruct、@PersistenceContext、@Resource、@PreDestroy等注解。

从今Spring提供的参考手册中我们深知该配置的力量是扫描配置的base-package包下的有着以了@Component注解的切近,并且以其活动注册及容器中,同时为扫描@Controller,@Service,@Respository这三只注解,因为她们是连续自@Component。

2.当applicationContext-MVC.xml中配置<mvc:annotation-driven />,负责SpringMVC相关注解的运用。

此外,还有一个同SpringMVC相关如下配置,经过验证,这个是SpringMVC必须使配备的,因为其声明了@RequestMapping、@RequestBody、@ResponseBody等。并且,该配置默认加载很多底参数绑定方法,比如json转换解析器等。

<mvc:annotation-driven />

2.applicationContext-MVC.xml中配置

俺们找到了起非可知科学跳转的因,那么它的解决办法是什么吗?

1.当applicationContext.xml中配置了<context:component-scan base-package=“com.hafiz.www”
/>,负责所有需要注册的Bean的扫描以及注册工作。

<context:component-scan base-package="com.winner" />

当Spring整体框架的着力概念被,容器是核心思想,就是用来保管Bean的满生命周期的,而在一个类别面临,容器不肯定只有一个,Spring中好包括多独容器,而且容器有上下层关系,目前极端广泛的同等栽情景就是是于一个品种蒙引入Spring和SpringMVC这有限独框架,那么它们事实上就是简单个容器,Spring是父容器,SpringMVC是其子容器,并且于Spring父容器中注册之Bean对于SpringMVC容器中是可见的,而以SpringMVC容器中注册之Bean对于Spring父容器中凡不可见的,也尽管是子容器可以瞥见父容器中之报的Bean,反的即特别。

<!-- Spring容器中注册非@controller注解的Bean -->
<context:component-scan base-package="com.winner">
   <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

可每当骨子里工程被见面席卷过多安排,我们本官方推荐根据不同的事务模块来划分不同容器中注册不同门类的Bean:Spring父容器负责所有其他非@Controller注解的Bean的挂号,而SpringMVC只当@Controller注解的Bean的登记,使得他们顶住、明确边界。配置方式如下

俺们共有Spring和SpringMVC两单容器,它们的配备文件分别吗applicationContext.xml和applicationContext-MVC.xml。

<!--配置注解控制器映射器,它是SpringMVC中用来将Request请求URL到映射到具体Controller-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!--配置注解控制器映射器,它是SpringMVC中用来将具体请求映射到具体方法-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
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());
}

spring3.1之后的版及以下配置方式等

protected boolean isHandler(Class<?> beanType) {
  return AnnotationUtils.findAnnotation(beanType, Controller.class) != null;
}

4.每当applicationContext-MVC.xml中安排<context:component-scan base-package=“com.hafiz.www”
/>,重开后,验证成功,springMVC跳反中。

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
   <property name="detectHandlerMethodsInAncestorContexts">
       <value>true</value>
   </property>
</bean>
<!--配置注解控制器映射器,它是SpringMVC中用来将Request请求URL到映射到具体Controller-->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<!--配置注解控制器映射器,它是SpringMVC中用来将具体请求映射到具体方法-->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>

 

  这样我们于亮了spring和springMVC的父子容器关系、以及扫描注册之原理以后,根据官方建议我们就足以十分好管不同类别的Bean分配到不同之容器中进行保管。再出现Bean找不交要SpringMVC不可知超越反和工作的布失效的题目,我们尽管好便捷的固化与缓解问题了

只要以第4步配置中,SpringMVC容器中呢注册了具有带有@Controller注解的Bean,故SpringMVC能找到电脑进行处理,从而正常跳转。

三、总结

<!-- SpringMVC容器中只注册带有@controller注解的Bean -->
<context:component-scan base-package="com.winner" use-default-filters="false">
   <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>

  我们注意到以initHandlerMethods()方法中,detectHandlerMethodsInAncestorContexts这个Switch,它根本控制得哪些容器被的bean以及是否连父容器,默认是匪包括的。所以解决办法就是在springMVC的配置文件中布局HandlerMapping的detectHandlerMethodsInAncestorContexts属性为true即可(这里需要根据现实项目看使用的凡啦种HandlerMapping),让她检测父容器的bean。如下:

相关文章

标签:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图