zoukankan      html  css  js  c++  java
  • springMVC WebApplicationInitializer 替代web.xml 配置Servlet 之原理

    Servlet 3.0之前 ,xml  配置 

    在过去搭建spring + springMCV ,首先第一步要做的是什么 ,就是要配置web.xml 文件 ,把springMVC 中的Servlet 加载到tomcat 。通过加载 dispatcher 来启动整个spring容器。web.xml 如下 。

      <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>
          org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>/WEB-INF/spring/dispatcher-config.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
      </servlet>
     
      <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>

     Servlet 3.0后 ,java 配置

    在Servlet 进入在3.0+时代后,Servlet 变支持了注解配置Servlet,而spring也推荐 java 代码的配置 。那么以上web.xml 配置Servlet,便可以通过实现WebApplicationInitializer 接口,来完成Servlet的配置 ,直接看代码,如下

    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRegistration.Dynamic;
    
    import org.springframework.web.WebApplicationInitializer;
    import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
    import org.springframework.web.servlet.DispatcherServlet;
    
    public class WebInitializer implements WebApplicationInitializer {// 1 实现接口
        @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            ctx.register(MyMvcConfig.class); //注册自己的配置文件
            ctx.setServletContext(servletContext); // 2 把 ServletContext 注入到spring容器中 
            Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx)); // 3 加载  dispatcher Servlet。
            servlet.addMapping("/");
            servlet.setLoadOnStartup(1);
        }
    }
    MyMvcConfig 为自己的配置java文件 。,这里做简单的为容器注入了试图解析器。
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    import org.springframework.web.servlet.view.InternalResourceViewResolver;
    import org.springframework.web.servlet.view.JstlView;
    
    @Configuration // 配置文件的支持
    @EnableWebMvc // 开启springMCV
    @ComponentScan("xxx") //扫描加载java文件 
    public class MyMvcConfig {
        @Bean
        public InternalResourceViewResolver viewResolver() {
            InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
            viewResolver.setPrefix("/WEB-INF/classes/views/");
            viewResolver.setSuffix(".jsp");
            viewResolver.setViewClass(JstlView.class);
            return viewResolver;
        }
    }
    ok  其实这样配置,部署到tomcat中 ,运行,就会启动 WebInitializer.onStartup 来启动spring中的各种组件 。

    原理分析

    在第一次接触到的时候还是和困惑?这个tomcat 是怎么时候,怎么来运行 WebInitializer.onStartup这个方法的呢。?一跟踪代码方法spring两个jar包中有这个代码的引用 ,一个是支持jetty的一个,web jar包 ,
    如下图,这里就只跟踪下web中的代码 ,对jetty就不研究了

    点进 SpringServletContainerInitializer 这个类,发现这个类 继承实现了 ServletContainerInitializer 这个接口 ,路径:javax.servlet.ServletContainerInitializer 。这个类可不是spring中的东西了 。完整代码 :

    package org.springframework.web;
    
    import java.lang.reflect.Modifier;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.ServiceLoader;
    import java.util.Set;
    import javax.servlet.ServletContainerInitializer;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.HandlesTypes;
    
    import org.springframework.core.annotation.AnnotationAwareOrderComparator;
    
    /
    @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) {
                initializer.onStartup(servletContext);
            }
        }
    
    }
    
    
    注意标记黄色部分,一看原来不就是,把所有 WebApplicationInitializer 遍历了一遍,然后调用了 onStartup 方法把 servletContext传进去吗。 而我们开始写的 WebInitializer就属于
    WebApplicationInitializer  ,所以我们的WebInitializer从这里开始运行。那么 ServletContainerInitializer 又 是怎么加载的? 这个就要跟tomcat那边的代码了,我猜,也是拿到 所有 ServletContainerInitializer  的实现类,运行了 onStartup方法 。



  • 相关阅读:
    iOS通知的使用
    使用代理和block写一个alertView
    MongoDB的访问权限和用户设置
    编写高效SQL语句
    Linux 安装 jdk 环境
    基于3dsMax的地图编辑器设想
    入驻cnBlogs!
    毕设开发总结3D游戏框架及网络对战游戏的开发(1)
    gkENGINE 个人图形引擎展示
    利用D3DQUERY实现简单的GPU计时器
  • 原文地址:https://www.cnblogs.com/jonrain0625/p/11291969.html
Copyright © 2011-2022 走看看