SSM项目中监听器中Service空指针问题

523 阅读2分钟

在SSM项目中是初始化加载Listener,实现启动程序时的一些操作

  1. 第一步创建listener类
package com.chenbro.datahub.listener;

import com.chenbro.datahub.model.Monitor;
import com.chenbro.datahub.model.ProdCount;
import com.chenbro.datahub.service.IMonitorService;
import com.chenbro.datahub.service.IProdCountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.annotation.PostConstruct;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.sql.Timestamp;

public class MonitorMachine implements ServletContextListener {

    public static MonitorMachine monitorMachine;

    private static WebApplicationContext springContext;


    IProdCountService prodCountService ;


    IMonitorService iMonitorService ;

    @PostConstruct
    public void init(){
        monitorMachine = this;
    }

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(servletContextEvent.getServletContext());
        prodCountService = springContext.getBean(IProdCountService.class);
        iMonitorService = springContext.getBean(IMonitorService.class);
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }
}

  1. 在web.xml文件中配置监听
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <listener>
    <listener-class>com.chenbro.datahub.listener.MonitorMachine</listener-class>
  </listener>
  1. Servlet容器初始化完成后,会调用监听器类中的contextInitialized方法。在监听器中无法通过注解的方式调用Service和Mapper。Spring框架管理和装配bean
    @Autowired
    IProdCountService prodCountService ;

    @Autowired
    IMonitorService iMonitorService ;
    
    //程序会抛出空指针异常,无法通过注解注入
    (1)Listener的生命周期是由servlet容器管理的,项目启动时的MonitorMachine是由servlet容器实例化并调用其contextInitialized方法,而servlet容器并不能识别@Autowired注解,因此导致prodCountService、iMonitorService实例注入失败。

    (2)而spring容器中的bean的生命周期是由spring容器管理的。
    
  1. 在Spring容器之外如何引用Spring容器的bean实例,可以使用Spring提供的WebApplicationContextUtils工具类,该工具类的作用是获取到spring容器的引用,进而获取到需要的bean实例
WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(servletContextEvent.getServletContext());
IProdCountService prodCountService = springContext.getBean(IProdCountService.class);

注意:
1.确保Servlet容器实例化监听器调用contextInitialized前,Spring容器已经初始化完毕
2.Spring的初始化由Listener(ContextLoaderListener)完成,首先得在web.xml配置Spring容器的Listener

配置文件顺序如下:
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <listener>
    <listener-class>com.chenbro.datahub.listener.MonitorMachine</listener-class>
  </listener>