第一节:Spring 与 SpringMVC 整合

一、Spring 与 SpringMVC 是否需要整合?

  1、需要进行 Spring 整合 SpringMVC 吗?
  2、还是否需要再加入 Spring 的 IOC 容器?
  3、是否需要再 web.xml 文件中配置启动的 Spring IOC 容器的 ContextLoaderListener?

  不需要整合:

    都放在 SpringMVC 的配置文件中,也可以分多个 Spring 的配置文件,然后使用 import 节点导入其他的配置文件

    示例:在 springmvc.xml 中导入 spring.xml 文件

    <import resource="spring.xml"/>

     不整合造成的问题:需要将 spring 管理的内容都交给 springMVC 管理,这样会造成业务逻辑混乱

  需要整合:

    通常情况下,类似于数据源、事务,整合其他框架都是放在 Spring 的配置文件中(而不是放在 SpringMVC 的配置文件中),实际上放入 Spring 配置文件对应的 IOC 容器中的还有 Service 和 Dao。

    整合的目的:分工明确

      SpringMVC的配置文件就来配置网站转发逻辑以及网站功能有关的(视图解析器、文件上传解析器、支持ajax)

      Spring的配置文件来配置和业务有关的(事务控制,数据源,xxx)

    

    整合:Spring 的配置文件在什么时候加载?怎么加载?

    注意:Spring 的配置文件必须在项目启动时加载,且要在 Servlet 加载前加载。

    解决方法:使用监听器(首先执行),可以在ServletContext 加载时,通过监听器加载 Spring 的配置文件,创建 Spring 容器,也可以使用 Spring 提供的监听器。

 

二、准备工作

  1、创建一个动态 Web 工程

  2、导入 jar 包依赖

   <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-version>4.1.0.RELEASE</spring-version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <!--  AOP  -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <!--  Web  -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>


        <dependency>
            <groupId>org.apache.taglibs</groupId>
            <artifactId>taglibs-standard-impl</artifactId>
            <version>1.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.taglibs</groupId>
            <artifactId>taglibs-standard-spec</artifactId>
            <version>1.2.1</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.4.Final</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.8</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.8</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.8</version>
        </dependency>


    </dependencies>

  3、创建 Spring 的配置文件 spring.xml(不扫描控制器和异常处理)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">


    <!--扫描组件,排除 controller 和 ControllerAdvice-->
    <context:component-scan base-package="com.njf" use-default-filters="true">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
    </context:component-scan>

<!-- 配置数据源,整合其他框架,事务等等 -->
</beans>

  4、配置 springMVC的配置文件 springmvc.xml(只扫描控制器和异常处理,和web相关的组件)

<?xml version="1.0" encoding="UTF-8"?>
<beans  xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:context="http://www.springframework.org/schema/context"
     xmlns:mvc="http://www.springframework.org/schema/mvc"
     xsi:schemaLocation="http://www.springframework.org/schema/mvc  http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
         http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    <!-- 扫描组件,将加上@Controller注解的类作为springMVC的控制层和异常控制器 -->
    <context:component-scan base-package="com.njf" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
    </context:component-scan>
     
     <!--  配置一个视图解析器 :能帮我们拼接页面地址-->
     <bean  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
         <property name="prefix"  value="/WEB-INF/view/"></property>
         <property name="suffix"  value=".jsp"></property>
     </bean>
     
     <!-- 处理静态资源,交给 Tomcat 处理 -->
     <mvc:default-servlet-handler/>
     
     <!-- 开启 SpringMVC 的高级功能 -->
     <mvc:annotation-driven />
     
     <!--
         处理文件,将客户端上传的File文件,处理为MultipartFile
         注意:文件解析器的bean中id必须设置为multipartResolver
      -->
     <bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
         <!-- 设置文件解析的编码,注意:一定要和页面的pageEncoding保持一致 -->
         <property name="defaultEncoding"  value="UTF-8"></property>
         <!-- 设置最大上传文件大小 -->
         <property name="maxUploadSize"  value="88888888"></property>
     </bean>
     
     <!-- 配置异常处理器 -->
     <bean  class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
         <property name="exceptionMappings">
              <props>
                  <prop  key="java.lang.NullPointerException">error</prop>
              </props>
         </property>
     </bean>

     <!-- <mvc:interceptors>
         默认拦截所有请求
         <bean  class="com.spring.interceptor.FirstInterceptor"></bean>
         <bean  class="com.spring.interceptor.SecondInterceptor"></bean>
         此方式要求拦截器类上必须加注解@Component
         <ref bean="firstInterceptor"/>
         
         设置自定义拦截方式
         <mvc:interceptor>
              <bean></bean>
              <mvc:mapping path=""/>
              <mvc:exclude-mapping path=""/>
         </mvc:interceptor>
     </mvc:interceptors> -->
</beans>

  5、存在的问题

    若 Spring 的 IOC 容器和 SpringMVC 的 IOC 容器扫描的包有重合的部分,就会导致有的 bean 会被创建两次。
    如果某个包下面的 bean 会被扫描多次,就会出现多个 bean 的问题。

  6、解决方案

    使用 Spring 的 IOC 容器扫描的包和 SpringMVC 的 IOC 容器扫描的包没有重合的部分,可以使用 exclude-filter 和 include-filter 子节点来规定只能扫描的注解:

    由于 SpringMVC 是对 Servlet 的封装,我们可以只用来扫描控制层;

    spring 的配置文件扫描除了控制层之外的 bean,还可以用于配置数据源,整合其他框架,事务等;

    具体配置如上。

三、自定义监听器整合Spring与SpringMVC

  1、自定义监听器

public class SpringListener implements ServletContextListener {

    public SpringListener() {
    }

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        //获取 application 对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        ServletContext servletContext = sce.getServletContext();
        // 把spring IOC 容器放到 application 域中
        servletContext.setAttribute("ac", ac);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}

  2、web.xml 中的配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
    </welcome-file-list>

    <!-- 配置自定义的监听器 -->
    <listener>
        <listener-class>com.njf.listener.SpringListener</listener-class>
    </listener>

    <!--  前端控制器(核心控制器)  -->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 配置DispatcherServlet的初始化參數:设置文件的路径和文件名称 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!--
           servlet 启动加载,servlet 原本是第一次访问创建对象
           load-on-startup:服务器启动的时候就创建对象,值越小优先级越高,越先创建对象
         -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!--
      /* 和 / 都是拦截所有请求,/:会拦截所有请求,但是不会拦截 *.jsp,能保证 jsp访问正常;
      /* 的范围更大,还会拦截 *.jsp 这些请求,一旦拦截 jsp 页面就不能显示了
    -->
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>     <!-- / 这样写,只有请求才处理,页面会过滤掉 -->
    </servlet-mapping>


    <!--  字符编码过滤器  -->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <!-- 设置字符编码 -->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <!-- 强制设置响应进行编码 -->
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>  <!-- 对所有的请求都拦截,处理所有响应-->
    </filter-mapping>

    <!-- REST 风格过滤器-->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

  3、控制器方法

    @RequestMapping(value = "/hello2")
    public String hello2(HttpSession session) {
        //获取spring IOC 所管理的 bean 组件
        ServletContext servletContext = session.getServletContext();
        ApplicationContext ac = (ApplicationContext)servletContext.getAttribute("ac");
        System.out.println(ac);
        BookService bookService = ac.getBean("bookService", BookService.class);
        System.out.println("bookService = " + bookService);
        return "success";
    }

    可以在控制器方法中通过 ServletContext 对象来获取 application 对象,从而进行操作。

 

四、使用Spring监听器进行整合

  1、使用 Spring 监听器

    在 web.xml 中进配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
    </welcome-file-list>

     <!-- 配置启动 Spring IOC容器的 Listener-->
     <listener>
         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
     </listener>

    <!--  前端控制器(核心控制器)  -->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 配置DispatcherServlet的初始化參數:设置文件的路径和文件名称 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!--
           servlet 启动加载,servlet 原本是第一次访问创建对象
           load-on-startup:服务器启动的时候就创建对象,值越小优先级越高,越先创建对象
         -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!--
      /* 和 / 都是拦截所有请求,/:会拦截所有请求,但是不会拦截 *.jsp,能保证 jsp访问正常;
      /* 的范围更大,还会拦截 *.jsp 这些请求,一旦拦截 jsp 页面就不能显示了
    -->
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>     <!-- / 这样写,只有请求才处理,页面会过滤掉 -->
    </servlet-mapping>


    <!--  字符编码过滤器  -->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <!-- 设置字符编码 -->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <!-- 强制设置响应进行编码 -->
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>  <!-- 对所有的请求都拦截,处理所有响应-->
    </filter-mapping>

    <!-- REST 风格过滤器-->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

    但是这是会在控制台报错:

java.lang.IllegalStateException: BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext

    这是因为没有找到 spring 的配置文件(可能是文件名错误或路径错误)

    还需要在 web.xml中 配置 <context-param> 标签,指定 spring.xml 的位置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
    </welcome-file-list>

    <!-- 配置 spring 容器,指定 spring 的配置文件 spring.xml-->
    <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring.xml</param-value>
    </context-param>

     <!-- 配置启动 Spring IOC容器的 Listener-->
     <listener>
         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
     </listener>

    <!--  前端控制器(核心控制器)  -->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 配置DispatcherServlet的初始化參數:设置文件的路径和文件名称 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!--
           servlet 启动加载,servlet 原本是第一次访问创建对象
           load-on-startup:服务器启动的时候就创建对象,值越小优先级越高,越先创建对象
         -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!--
      /* 和 / 都是拦截所有请求,/:会拦截所有请求,但是不会拦截 *.jsp,能保证 jsp访问正常;
      /* 的范围更大,还会拦截 *.jsp 这些请求,一旦拦截 jsp 页面就不能显示了
    -->
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>     <!-- / 这样写,只有请求才处理,页面会过滤掉 -->
    </servlet-mapping>


    <!--  字符编码过滤器  -->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <!-- 设置字符编码 -->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <!-- 强制设置响应进行编码 -->
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>  <!-- 对所有的请求都拦截,处理所有响应-->
    </filter-mapping>

    <!-- REST 风格过滤器-->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

    如果没有配置此标签,监听器默认会去 web-content 下找 application.xml的配置文件,找不到,就会报上面的错误,如果使用了该标签,就可以指定配置文件的路径和名称了。

    扩展:web.xml中的执行顺序
    1、首先加载的是 <context-parm> ,里面存放的当前 web 应用的参数和配置
    2、运行监听器
    3、运行过滤器
    4、运行 Servlet

  

  2、ContextLoaderListener 部分源码

public class ContextLoaderListener extends  ContextLoader implements ServletContextListener {
   
     public ContextLoaderListener() {
     }
    
     public ContextLoaderListener(WebApplicationContext  context) {
         super(context);
     }
    
     @Override
     public void contextInitialized(ServletContextEvent  event) {
         initWebApplicationContext(event.getServletContext());
     }
    
     @Override
     public void contextDestroyed(ServletContextEvent  event) {
         closeWebApplicationContext(event.getServletContext());
         ContextCleanupListener.cleanupAttributes(event.getServletContext());
     }
}


initWebApplicationContext 方法源码:

    public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
        if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
            throw new IllegalStateException(
                    "Cannot initialize context because there is already a root application context present - " +
                    "check whether you have multiple ContextLoader* definitions in your web.xml!");
        }

        Log logger = LogFactory.getLog(ContextLoader.class);
        servletContext.log("Initializing Spring root WebApplicationContext");
        if (logger.isInfoEnabled()) {
            logger.info("Root WebApplicationContext: initialization started");
        }
        long startTime = System.currentTimeMillis();

        try {
            // Store context in local instance variable, to guarantee that
            // it is available on ServletContext shutdown.
            if (this.context == null) {
                this.context = createWebApplicationContext(servletContext);
            }
            if (this.context instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
                if (!cwac.isActive()) {
                    // The context has not yet been refreshed -> provide services such as
                    // setting the parent context, setting the application context id, etc
                    if (cwac.getParent() == null) {
                        // The context instance was injected without an explicit parent ->
                        // determine parent for root web application context, if any.
                        ApplicationContext parent = loadParentContext(servletContext);
                        cwac.setParent(parent);
                    }
                    configureAndRefreshWebApplicationContext(cwac, servletContext);
                }
            }
            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

            ClassLoader ccl = Thread.currentThread().getContextClassLoader();
            if (ccl == ContextLoader.class.getClassLoader()) {
                currentContext = this.context;
            }
            else if (ccl != null) {
                currentContextPerThread.put(ccl, this.context);
            }

            if (logger.isDebugEnabled()) {
                logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
                        WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
            }
            if (logger.isInfoEnabled()) {
                long elapsedTime = System.currentTimeMillis() - startTime;
                logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
            }

            return this.context;
        }
        catch (RuntimeException ex) {
            logger.error("Context initialization failed", ex);
            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
            throw ex;
        }
        catch (Error err) {
            logger.error("Context initialization failed", err);
            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
            throw err;
        }
    }

五、父子容器

  Spring Ioc 容器 与 SpringMVC Ioc 容器的关系
  SpringMVC 的 Ioc 容器中的 bean 可以来应用 Spring Ioc 容器中的 bean,返回来却不行!Spring Ioc 容器中的 bean 却不能引用 SpringMVC Ioc 容器中的 bean。
  spring 是父容器,springMVC 是子容器
 
  规定:子容器能够调用访问父容器中的 bean,而父容器不能够调用访问子容器中的 bean
 
  1、在 SpringMVC 配置文件中引用业务层的 Bean;
  2、多个 Spring IOC容器之间设置为父子关系,以实现良好的解耦;
  3、SpringMVC WEB 层容器可作为 “业务层”,Spring 容器的子容器:即 WEB 层容器可以引用业务层容器的 Bean,而业务层容器却访问不到 WEB 层容器的 Bean;
  
  Spring 管理业务逻辑组件
  SpringMVC 管理控制器组件

六、SpringMVC 对比 Struts2

    1、SpringMVC 的入口是 Servlet,而 Struts2 是Filter;
    2、SpringMVC 会稍微比 Struts2 快些,SpringMVC 是基于方法设计,而 Struts2 是基于类,每次发送一次请求都会实例一个 Action;
    3、SpringMVC 使用更加简洁,开发效率 SpringMVC确实比 struts2 高,支持 JSR303,处理 AJAX 的请求更方便;
    4、 Struts2 的 OGNL 表达式使页面的开发效率相比 Spring MVC 更高些;
 
 
原文地址:https://www.cnblogs.com/niujifei/p/15661522.html