zoukankan      html  css  js  c++  java
  • spring学习(十二)--spring中WebApplicationInitializer解析

      上文中讲解了如何通过WebApplicationInitializer取代Web.xml进行spring容器的启动,WebApplicationInitializer是一个接口,通过实现WebApplicationInitializer,在其中可以添加servlet,listener等。在Web容器启动的时候,spring-web会通过SPI机制,加载这个接口的实现类,从而起到web.xml相同的作用。下面就看一下这个接口的详细内容:

    public interface WebApplicationInitializer {
        void onStartup(ServletContext servletContext) throws ServletException;
    
    }

    WebApplicationInitializer只有一个方法,比较简单,看不出什么头绪。在WebApplicationInitializer同级别有个SpringServletContainerInitializer类,我们来看下这个类的代码:

    package org.springframework.web;
    
    @HandlesTypes(WebApplicationInitializer.class)
    public class SpringServletContainerInitializer implements ServletContainerInitializer {
    
        @Override
        public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
                throws ServletException {
    
            List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();
    
            if (webAppInitializerClasses != null) {
                for (Class<?> waiClass : webAppInitializerClasses) {
                    // Be defensive: Some servlet containers provide us with invalid classes,
                    // no matter what @HandlesTypes says...
                    if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
                            WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
                        try {
                            initializers.add((WebApplicationInitializer) waiClass.newInstance());
                        }
                        catch (Throwable ex) {
                            throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
                        }
                    }
                }
            }
    
            if (initializers.isEmpty()) {
                servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
                return;
            }
    
            AnnotationAwareOrderComparator.sort(initializers);
            servletContext.log("Spring WebApplicationInitializers detected on classpath: " + initializers);
    
            for (WebApplicationInitializer initializer : initializers) {
           //这里指定了调用的类的方法,onStartup() initializer.onStartup(servletContext); } } }

    SpringServletContainerInitializer这个类里也有个onStartup方法,看一下它的逻辑。首先判断webAppInitializerClasses这个set是否有值,如果有值,就找出里边不是接口、不是抽象类、实现了WebApplicationInitializer接口的类,保存到一个LinkedList中。

    如果最终这个list为空,就返回空。如果最终list不为空,则按照一定顺序排序,将这些类实例化,调用其中的onStartup方法。

    一旦我们实现了WebApplicationInitializer这个接口,spring-web就能扫描到WebApplicationInitializer的实现类,调用其中的onStartup方法,实现加载spring配置文件的目的。

    但是,在web容器启动的时候,SpringServletContainerInitializer这个类又是怎么随着容器启动被调用呢?我们看一下SpringServletContainerInitializer这个类,它实现了ServletContainerInitializer接口,我们看一下ServletContainerInitializer接口代码:

    public interface ServletContainerInitializer
    {
        public abstract void onStartup(Set set, ServletContext servletcontext)
            throws ServletException;
    }

    ServletContainerInitializer这个类,是javax.servlet-api包下的类。

    SpringServletContainerInitializer类中解释到,它实现了ServletContainerInitializer,通过SPI机制,当web容器启动时候,会到spring-web包的MATE-INF/services文件夹下扫描配置文件,在MATE-INF/services下有一个配置文件,文件名为ServletContainerInitializer接口全路径,文件内容为ServletContainerInitializer实现类的全路径,web容器扫描到该配置文件后,会将实现类实例化,我们看一下MATE-INF/services文件夹:

    这样,web容器启动时,通过SPI机制,找到ServletContainerInitializer接口的实现类SpringServletContainerInitializer,将SpringServletContainerInitializer实例化,调用SpringServletContainerInitializer的onStartup方法,SpringServletContainerInitializer通过@HandlesTypes将WebApplicationInitializer注入进来,并调用WebApplicationInitializer的onStartup方法。至此,通过实现WebApplicationInitializer接口的onStartup方法,实现spring随着容器启动而被初始化。

    个人理解,如有错误,欢迎指正!
  • 相关阅读:
    linux c使用socket进行http 通信,并接收任意大小的http响应(四)
    linux c使用socket进行http 通信,并接收任意大小的http响应(三)
    Linux c读取系统内存使用信息
    linux c使用socket进行http 通信,并接收任意大小的http响应(二)
    linux c使用socket进行http 通信,并接收任意大小的http响应(一)
    Linux c读取任意大小文件的所有数据
    Linux c 从文件当中读取任意一行的数据
    如何抓取Android系统APP运行测试日志
    Linux下将Weblogic设置为开机启动
    Red hat/CentOS7关闭防火
  • 原文地址:https://www.cnblogs.com/gllegolas/p/11731292.html
Copyright © 2011-2022 走看看