ContextLoaderListener的作用以及Spring和JavaWeb或SpringMVC的整合问题

一、背景

1、Spring整合Javaweb的时候,在Servlet类上,不能使用@Cotroller属性。
因为javaweb项目在Tomcat容器启动的时候会自动加载Servlet对象,此时若加上@Controller,ioc容器一启动,也存在了Servlet对象。而Tomcat中的Servlet对象和IOC容器中的Servlet对象不同,在Tomcat中当然是使用Tomcat创建的Servlet对象。因此目前不能标注Spring注解在servlet层;其他层可以标注
在这里插入图片描述

在这里插入图片描述
2、既然如此,不在Servlet类中标注@Controller注解,就不能使用IOC容器提供的强大功能,@Autowired也会失效,该怎么解决?
于是乎,在工具类WebUtils中使用静态方法初始化ioc容器,并写一个getBean方法,每次,Servlet要调用IOC容器中的某个对象的话,通过WebUtils的getBean方法即可调,此时就可以享受IOC容器中对象的强大功能(事务控制等等)
在这里插入图片描述

3、在需要的Servlet类上调用WebUtils的getBean方法,这样子每次请求过来调用Servlet类,Servlet类会调用WebUtils类,这样子在WebUtils中声明的ioc容器也跟着初始化完成。Servlet类就可以调用ioc容器中强大的对象了。
在这里插入图片描述
4、但是这样子处理存在很多问题,每次ioc容器的初始化,并没有销毁,还有多线程等其他各种问题。于是乎,Spring早考虑到这一点,在spring-web包提供了一个ContextLoaderListener来解决这个问题。这个监听器负责ioc容器的初始化销毁各种问题等工作。

<!-- needed for ContextLoaderListener -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    <!-- Bootstraps the root web application context before servlet initialization -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

可以查看监听器源码,这里的WebApplicationContext其实是ApplicationContext的实现类,也就是所谓的ioc容器了。
在这里插入图片描述

然后需要使用ioc容器对象的时候调用ContextLoader中的getCurrentWebApplication即可解决。
在这里插入图片描述

二、背景二

1、那么,若Spring整合SpringMVC呢?SpringMVC启动DispatcherServlet也会初始化ioc容器,Spring也有ioc容器。怎么在项目中两个配置文件整合起来?
而且SpringMVC和Spring整合要求的目的;就是要分工明确;

  • SpringMVC的配置文件就来配置和网站转发逻辑以及网站功能有关的(视图解析器,文件上传解析器,支持ajax,xxx);
  • Spring的配置文件来配置和业务有关的(事务控制,数据源,xxx);

在这里插入图片描述
2、可以使用<import resource="spring.xml"/>合并配置文件下面可以看出使用SpringMVC调用DispatcherServlet,把两个xml文件读取并且初始化完成ioc 容器。
在这里插入图片描述
3、但是推荐Spring和SpringMVC分容器使用,Spring用自己的容器,SpringMVC用自己的容器,用两个容器干活。因为两个文件合并一起的话,系统一启动(springmvc调用DispatherServlet初始化了ioc),只有一个大ioc容器(springmvc中的ioc)干活,万一其中的一个小ioc.xml炸了,整个ioc容器也就炸了,而且随着项目的增大,xml配置文件信息也混乱。可以在web.xml文件中配置ContextLoaderListener这个监听器,这样子Spring的ioc容器也启动了,系统中也存在了Spring的ioc容器对象。
在这里插入图片描述
Tomcat一启动,就会初始化Spring的ioc容器,同时初始化SpringMVC的DispatchrServlet的时候也完成了SpringMVC的ioc容器。
在这里插入图片描述4、但是这样子又存在问题:由于Spring的配置文件扫描的是整个包,SpringMVC的配置文件也是扫描整个包,这样子系统中两个ioc容器就都存在相同的对象了,而且SpringMVC在调用Controller层的时候还不会报错,而且会调用SpringMVC的ioc容器中自己的BookService对象,这样子,在spring中对BookService对象配置的事务控制就不能用了
在这里插入图片描述
5、于是乎,SpringMVC和Spring两个容器在扫描的时候应该各司其职。
Spring管理业务逻辑组件:

<context:component-scan base-package="com.atguigu">
    <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>

而SpringMVC管理控制器组件:

<context:component-scan base-package="com.atguigu" 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>

6、在Controller层调用spring的ioc容器中对象(即SpringMVC的@Controller的对象调用Spring的@Service标注的对象)是可以。
但是在Service层调用SpringMVC的ioc容器中的对象(即Spring的@Service标注的对象调用SpringMVC的@Controller标注的对象)会报错。如下:
在这里插入图片描述
在这里插入图片描述
这里涉及到父子容器的问题:
在分容器下,Spring是一个父容器,SpringMVC是一个子容器;
子容器还可以引用父容器的组件;父容器不能引用子容器的组件;

在这里插入图片描述

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页