zoukankan      html  css  js  c++  java
  • springmvc web.xml配置之 -- ContextLoaderListener

    首先回归一下web.xml的常用配置,看一个示例:

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring/applicationcontext-*.xml</param-value>
    </context-param>
    
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <filter>
        <filter-name>encodingFilter</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>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:spring/springmvc-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    View Code

    了解web.xml的作用之前必须要了解web容器(也称为是servlet容器)这个概念,常用的web容器有Tomcat、Jetty、JBoss等。

    使用web容器,就不得不清楚什么是ServletContext。ServletContext中的信息都是由容器提供的,在web容器启动时,它作为为公共环境容器存放公共信息,为各个Servlet提供信息,也可以作为各个Servlet之间通信的桥梁。

    将应用部署到web容器中,启动web容器后,web容器会读取web.xml中的配置信息,对ServletContext进行信息补充。(注:配置加载顺序为:context-param -> listener -> filter -> servlet)

    好了,回到本文主题。

    ContextLoaderListener

    web.xml中的配置文件中ContextLoaderListener作为监听器,会监听web容器相关事件,在web容器启动或者关闭时触发执行响应程序。具体地,ContextLoaderListener继承ContextLoader类并实现了ServletContextListener接口。

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

      

    1.关于监听

    ServletContextListener接口中只有初始化和销毁的两个方法::

    public interface ServletContextListener extends EventListener {
        /**
         ** Notification that the web application initialization
         ** process is starting.
         ** All ServletContextListeners are notified of context
         ** initialization before any filter or servlet in the web
         ** application is initialized.
         */
        public void contextInitialized ( ServletContextEvent sce );
    
        /**
         ** Notification that the servlet context is about to be shut down.
         ** All servlets and filters have been destroy()ed before any
         ** ServletContextListeners are notified of context
         ** destruction.
         */
        public void contextDestroyed ( ServletContextEvent sce );
    }

    也就是监听ServletContext的状态,ServletContext属于容器对象,在用于在容器开启或关闭时触发事件,执行contextInitialized/contextDestroyed 。如果想了解程序执行原由可以先了解事件监听设计模式。查阅Tomcat源码,tomcat触发ServletContext初始化监听事件的源码如下:

    ...(部分略)
       
    Object instances[] = getApplicationLifecycleListeners();
    for (int i = 0; i < instances.length; i++) {
        if (!(instances[i] instanceof ServletContextListener))
            continue;
        ServletContextListener listener = (ServletContextListener) instances[i];
        try {
            if (noPluggabilityListeners.contains(listener)) {
                listener.contextInitialized(tldEvent);
            } else {
                listener.contextInitialized(event);
            }
        } catch (Throwable t) {
        }
    }
    
     ...(部分略)

    也就是,遍历所有ServletContextListener,调用监听方法。

     

    2.关于功能

    关于功能主要看initWebApplicationContext()方法。 ContextLoader中的initWebApplicationContext()方法中会创建WebApplicationContext上下文对象,并将这个对象设置到servletContext中:

    ContextLoaderListener加载过程:

    2.1 创建IOC容器

    initWebApplicationContext调用createWebApplicationContext方法;

    -->createWebApplicationContext 调用determineContextClass方法

    --> defaultStrategies中加载配置文件:

    defaultStrategies.getProperty(WebApplicationContext.class.getName())

    ContextLoader 类中有段静态代码:

    static {
            try {
                ClassPathResource resource = new ClassPathResource(
                        "ContextLoader.properties", ContextLoader.class);
                defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
            } catch (IOException ex) {
                throw new IllegalStateException(
                        "Could not load 'ContextLoader.properties': "
                                + ex.getMessage());
            }
    
            currentContextPerThread = new ConcurrentHashMap(1);
        }

    ContextLoader.properties 文件内容如下:

    org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

    可知,默认加载的WebApplicationContext是XmlWebApplicationContext

    题外话,如果你不想使用默认的,在web.xml中配置contextClass即可

    protected Class<?> determineContextClass(ServletContext servletContext) {
            String contextClassName = servletContext.getInitParameter("contextClass");
            if(contextClassName != null) {
                try {
                    return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
                    ...(略)

    也就是这种形式:

    <context-param>
        <param-name>contextClass</param-name>
        <param-value>webApplicationContext类全路径名称</param-value>
    <context-param>

    org.springframework.web.context.support包下查询webApplicationContext。

    2.1 IOC容器配置加载,初始化

    这一步主要是调用configureAndRefreshWebApplicationContext,可知在上一步中创建了WebApplicationContext对象(ConfigurableApplicationContext类型),也就是创建了IOC容器对象,接着就要给这个对象进行配置参数的设置了。

    protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
            String configLocationParam;
            if(ObjectUtils.identityToString(wac).equals(wac.getId())) {
                configLocationParam = sc.getInitParameter("contextId");
                if(configLocationParam != null) {
                    wac.setId(configLocationParam);
                } else {
                    wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath()));
                }
            }
    
            wac.setServletContext(sc);
            configLocationParam = sc.getInitParameter("contextConfigLocation");
            if(configLocationParam != null) {
                wac.setConfigLocation(configLocationParam);
            }
    
            ConfigurableEnvironment env = wac.getEnvironment();
            if(env instanceof ConfigurableWebEnvironment) {
                ((ConfigurableWebEnvironment)env).initPropertySources(sc, (ServletConfig)null);
            }
    
            this.customizeContext(sc, wac);
            wac.refresh();
        }

    可知,首先会给WebApplicationContext对象设置ServletContext全局信息,然后读取><param-name>contextConfigLocation</param-name>对应的.xml中的配置信息,例如:

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring/applicationcontext-*.xml</param-value>
    </context-param>

    这些applicationcontext-*.xml配置文件中的信息之后再执行ConfigurableApplicationContext.refresh()方法就会被加载到IOC容器中。

    IOC容器的初始化过程,参考下一篇文章。

     

  • 相关阅读:
    WINCE6.0新建工程编译出错的问题
    单片机C语言中的data,idata,xdata,pdata,code
    WinCE 6.0学习笔记一
    Visual Studio 2005 学习笔记一 入门
    Zigbee系列 学习笔记六(设置项)
    Zigbee系列 学习笔记五(信道选择)
    Zigbee系列 学习笔记四(睡眠及唤醒)
    Zigbee系列 学习笔记三(初始化程序解析)
    Zigbee调试问题 IAR编译出现 Fatal Error[e72]: Segment BANKED_CODE must be defined in a segment definition option (-Z, -b or -P)
    关于懒设计
  • 原文地址:https://www.cnblogs.com/chenjunjie12321/p/9357534.html
Copyright © 2011-2022 走看看