Spring集成web环境-ContextLoaderListener监听器的分析

Posted bfhonor

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring集成web环境-ContextLoaderListener监听器的分析相关的知识,希望对你有一定的参考价值。

一、Spring与Web环境集成

1. ApplicationContext应用上下文获取方式

  • 通过上次Spring集成web环境-基本三层架构环境搭建文章,我们可以了解到应用上下文对象是通过new ClasspathXmlApplicationContext(spring配置文件)方式获取的,但是每次从容器中获得Bean时都要编写new ClasspathXmlApplicationContext(spring配置文件),这样的弊端是配置文件加载多次,应用上下文对象创建多次。
  • Web项目中,可以使用ServletContextListener监听Web应用的启动,我们可以在Web应用启动时,就加载Spring的配置文件,创建应用上下文对象ApplicationContext,在将其存储到最大的域servletContext域中,这样就可以在任意位置从域中获得应用上下文ApplicationContext对象了。

2. 自定义ContextLoaderLister

package com.itheima.listener;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class ContextLoaderListener implements ServletContextListener 

    //contextInitialized上下文初始化的方法
    //服务器一启动,只要监听到就会执行此方法
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) 
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        //将Spring的应用上下文对象存储到ServletContext域中
        ServletContext servletContext = servletContextEvent.getServletContext();
        servletContext.setAttribute("app",app);
        System.out.println("spring容器创建完毕...");
    
    //contextDestroyed上下文销毁的方法
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) 
    

  • src\\main\\webapp\\WEB-INF里面配置web.xml,添加listener监听器
<!--配置监听器-->
<listener>
    <listener-class>com.itheima.listener.ContextLoaderListener</listener-class>
</listener>
  • 此时倘若我们运行tomcat服务器,我们可以通过控制台看出一下结果,表示此时服务器启动,但是我们没有访问也会将spring容器创建成功,如果去访问服务器的时候,就不会再次创建了,直接从服务器里面拿就可以。

3. 自定义ContextLoaderLister代码优化①

  • ❌❌❌由于在上述的文件中,我们可以看到ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");是写死的,并且applicationContext.xml文件是随机命名的,命名成其他形式也是可以的;只不过在这里我们约定俗成的把它命名为applicationContext.xml,万一后期我们不适用这个名字,使用其他的名字;那就无法使用了❌❌❌
  • 所以我们需要将ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");提取到配置文件里面
  • web.xml文件里面添加如下配置
<!--全局齿初始化参数-->
<context-param>
    <param-name>contextConfigLocation</param-name><!--命名什么类型都可以-->
    <param-value>applicationContext.xml</param-value><!--填写配置文件的名称-->
</context-param>
  • 然后修改src\\main\\java里面com.itheima.listener包下的ContextLoaderListener.java文件
package com.itheima.listener;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class ContextLoaderListener implements ServletContextListener 

    //contextInitialized上下文初始化的方法
    //服务器一启动,只要监听到就会执行此方法
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) 
        ServletContext servletContext = servletContextEvent.getServletContext();//👈先提取到ServletContext

        //👇然后读取web.xml中的全局参数
        String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");

        ApplicationContext app = new ClassPathXmlApplicationContext(contextConfigLocation);
        //将Spring的应用上下文对象存储到ServletContext域中
        servletContext.setAttribute("app",app);
        System.out.println("spring容器创建完毕...");
    
    //contextDestroyed上下文销毁的方法
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) 

4. 自定义ContextLoaderLister代码优化②

  • src\\main\\java文件com.itheima.web包下的UserServlet.java文件
ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");
  • ❌❌❌其中的“app”也是耦合死的,这导致我们每次都需要记住app,然后再去其他文件里面创建。❌❌❌
  • src/main/java文件com.itheima.listener包里面创建WebApplicationContextUtils.java工具类
package com.itheima.listener;
import org.springframework.context.ApplicationContext;
import javax.servlet.ServletContext;

public class WebApplicationContextUtils 
    public static ApplicationContext getWebApplicationContext(ServletContext servletContext)
        return (ApplicationContext) servletContext.getAttribute("app");
    

  • src/main/java文件com.itheima.web包里面修改UserServlet.java文件
package com.itheima.web;

import com.itheima.listener.WebApplicationContextUtils;
import com.itheima.service.UserService;
import org.springframework.context.ApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class UserServlet extends HttpServlet 
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
        ServletContext servletContext = this.getServletContext();

        //ApplicationContext app = (ApplicationContext) servletContext.getAttribute("app");
        //👇此时已经替代了具体的字符串“app”,已经解耦合❗❗❗
        ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);

        UserService userService = app.getBean(UserService.class);
        userService.save();
    


  • 以上是我们对于Spring提供获取上下文工具底层封装的逐步了解和实现,方便我们理解和掌握。
  • 下面我们可以直接使用Spring自动提供的获取应用上下文工具

5. Spring提供获取应用上下文的工具

  • 上面的分析不用手动实现,Spring提供了一个监听器ContextLoaderListener就是对上述功能的封装,该监听器内部加载Spring配置文件,创建应用上下文对象,并存储到ServletContext域中,提供了一个客户端工具WebApplicationContextUtils供使用者获得应用上下文对象。

  • 所以我们需要做的只有两件事:
    ①在web.xml中配置ContextLoaderListener监听器(导入spring-web坐标)
    ②使用WebApplicationContextUtils获得应用上下文对象ApplicationContext

(1)导入Spring集成web的坐标

  • 在pom.xml文件中导入坐标
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.0.5.RELEASE</version>
</dependency>

(2)配置ContextLoaderListener监听器

  • 在web.xml文件中配置监听器
<!--全局参数-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--Spring的监听器-->
<listener>
	<listener-class>
       org.springframework.web.context.ContextLoaderListener
   </listener-class>
 </listener>

(3)通过工具获得应用上下文对象

  • 在web层代码,src\\mian\\java文件里面com.itheima.web包里面的UserServlet.java文件
ApplicationContext applicationContext =    
    WebApplicationContextUtils.getWebApplicationContext(servletContext);
    Object obj = applicationContext.getBean("id");
package com.itheima.web;

import com.itheima.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class UserServlet extends HttpServlet 
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
        ServletContext servletContext = this.getServletContext();

		//调用org.springframework.web.context.support包下的WebApplicationContextUtils工具类,Spring已经为我们封装好
        ApplicationContext app = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);

        UserService userService = app.getBean(UserService.class);
        userService.save();
    

以上是关于Spring集成web环境-ContextLoaderListener监听器的分析的主要内容,如果未能解决你的问题,请参考以下文章

Spring - Spring集成web环境 -基本三层架构搭建案例

Spring -- 集成web环境

Spring集成web环境-ContextLoaderListener监听器的分析

Spring集成web环境-ContextLoaderListener监听器的分析

Spring集成web环境-ContextLoaderListener监听器的分析

Spring集成web环境-ContextLoaderListener监听器的分析