springMVC容器和Spring容器

  • Spring和springMVC父子容器的关系

    1,Spring容器的启动是先于SpringMVC容器的,所以spring容器是不知道springMVC容器
    的存在的。也就是说父容器无法使用子容器的bean。

    2,当父容器初始化好之后,会将自己放到servletcontext的属性中:

    servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEX	T_ATTRIBUTE, this.context);
    

    那么,子容器在初始化时,就能得到父容器的存在。子容器可以使用父容器的bean。

  • 为什么Controller注册在父容器中,注册在子容器中时,springMVC无法处理请求呢?

    我们共有Spring和SpringMVC两个容器,它们的配置文件分别为applicationContext.xml和applicationContext-MVC.xml。
    1.在applicationContext.xml中配置了,负责所有需要注册的Bean的扫描和注册工作。
    2.在applicationContext-MVC.xml中配置,负责SpringMVC相关注解的使用。
    3.启动项目我们发现SpringMVC无法进行跳转,将log的日志打印级别设置为DEBUG进行调试,发现SpringMVC容器中的请求好像没有映射到具体controller中。
    4.在applicationContext-MVC.xml中配置,重启后,验证成功,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能找到处理器进行处理,从而正常跳转。

    在实际工程中会包括很多配置,我们按照官方推荐根据不同的业务模块来划分不同容器中注册不同类型的Bean:Spring父容器负责所有其他非@Controller注解的Bean的注册,而SpringMVC只负责@Controller注解的Bean的注册,使得他们各负其责、明确边界。配置方式如下

    1.在applicationContext.xml中配置:

    
    
       
    
    

    2.applicationContext-MVC.xml中配置

    
    
       
    
    
  • 父子容器说明
    1、父容器(使用listener监听器来加载配置文件):

       
      org.springframework.web.context.ContextLoaderListener   
    
    

    Spring 会创建一个WebApplicationContext,称为父容器),保存在 ServletContext中,key是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值。

    可以使用Spring提供的工具类取出r容器对象:WebApplicationContextUtils.getWebApplicationContext(ServletContext);

    2、子容器(使用Spring MVC 来处理拦截相关的请求时,会配置DispatchServlet):

    
        dispatcherServlet
        
        	org.springframework.web.servlet.DispatcherServlet
        
        
            contextConfigLocation
            /WEB-INF/applicationContext-mvc.xml
        
        1
    
     
    
        dispatcherServlet
        /
    
    

    每个DispatchServlet会有一个自己的容器,称为子容器,它也保存在 ServletContext中,key 是"org.springframework.web.servlet.FrameworkServlet.CONTEXT"+Servlet名称。当一 个Request对象产生时,会把这个子容器对象(WebApplicationContext)保存在Request对象中,key是 DispatcherServlet.class.getName() + “.CONTEXT”。

    可以使用工具类取出容器对象:RequestContextUtils.getWebApplicationContext(request);

    3、父容器和子容器的访问权限:

    子容器访问父容器中的bean,但是父容器不可以访问子容器中的bean。

    父容器使用与否:

    ①: 方案一,传统型:

    父容器中保存数据源、服务层、DAO层、事务的Bean。
    子容器中保存Mvc相关的Action的Bean.
    事务控制在服务层。
    由于父容器不能访问子容器中内容,事务的Bean在父容器中,无法访问子容器中内容,就无法对子容器中Action进行AOP(事务)。

    ②:方案二,激进型:

    Java世界的“面向接口编程”的思想是正确的,但在增删改查为主业务的系统里,Dao层接口,Dao层实现类,Service层接口,Service层实现类,Action父类,Action。再加上众多的O(vo\po\bo)和jsp页面。写一个小功能 7、8个类就写出来了。 开发者说我就是想接点私活儿,和PHP,ASP抢抢饭碗,但我又是Java程序员。最好的结果是大项目能做好,小项目能做快。所以“激进型”方案就出现了-----没有接口、没有Service层、还可以没有众多的O(vo\po\bo)。那没有Service层事务控制在哪一层?只好上升的Action层。

    本文不想说这是不是正确的思想,我想说的是Spring不会限制你这样做。

    由于有了父子容器,你将无法实现这一目标。解决方案是只使用子容器,不要父容器 。所以数据源、服务层、DAO层、事务的Bean、Action的Bean都放在子容器中。就可以实现了,事务(注解事务)就正常工作了。这样才够激进。

    总结:不使用listener监听器来加载spring的配置文件,只使用DispatcherServlet来加载spring的配置,不要父子容器,只使用一个DispatcherServlet,事情就简单了,什么麻烦事儿也没有了。

你可能感兴趣的:(spring)