【SpringMVC源码解析】 ServletContainerInitializer && SpringMVC源码入口解析

1 ServletContainerInitializer

在web容器启动时为提供给第三方组件机会做一些初始化的工作,servlet规范(JSR356)中通过ServletContainerInitializer实现此功能。每个框架要使用ServletContainerInitializer就必须在对应的jar包的META-INF/services 目录创建一个名为javax.servlet.ServletContainerInitializer的文件,文件内容指定具体的ServletContainerInitializer实现类,那么,当web容器启动时就会运行这个初始化器做一些组件内的初始化工作。

(1) 创建JAVA-WEB项目
在这里插入图片描述
(2) 创建接口及接口相关类

public interface ZrsService {

}

public interface ZrsServiceExtend extends ZrsService {

}

public abstract class AbstractZrsService implements ZrsService {

}

public class ZrsServicImpl implements ZrsService {

}

(3) 创建ServletContainerInitializer接口实现类

/**
* @Description: HandlesTypes,获取当前接口所有相关的类
* @Auther: zhurongsheng
* @Date: 2020/3/5 15:14
*/
@HandlesTypes(value = {ZrsService.class})
public class ZrsServletContainerInitializer implements ServletContainerInitializer {
    @Override
    public void onStartup(Set<Class<?>> classs, ServletContext servletContext) throws ServletException {
        System.out.println("################################");
        for (Class clazz:classs){
            System.out.println(clazz);
        }
    }
}

(4) 在META-INF/services 下创建 javax.servlet.ServletContainerInitializer

com.servlet.ZrsServletContainerInitializer

(5) 工程结构
在这里插入图片描述
(6) 启动tomcat,发现调用了ZrsServletContainerInitializer onStartup方法
在这里插入图片描述

2 SpringMVC环境准备

(1) 创建maven 工程
在这里插入图片描述

(2) 删除webapp下所有*.xml文件
在这里插入图片描述
(3) 引入依赖

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.0.6.RELEASE</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
  </dependency>
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.6</version>
  </dependency>
</dependencies>
<build>
  <plugins>
    <plugin>
      <artifactId>maven-compiler-plugin</artifactId>
      <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <encoding>UTF-8</encoding>
        <compilerArguments>
          <extdirs>${basedir}/src/main/webapp/WEB-INF/lib</extdirs>
        </compilerArguments>
      </configuration>
    </plugin>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-war-plugin</artifactId>
      <version>2.4</version>
      <configuration>
        <failOnMissingWebXml>false</failOnMissingWebXml>
      </configuration>
    </plugin>
  </plugins>
</build>

3 查看spring-web包
在这里插入图片描述

4 初步分析SpringServletContainerInitializer

(1) 源码分析,初始化WebApplicationInitializer接口的bean,并且调用WebApplicationInitializer实现类的onStartup方法

/**
* 获取WebApplicationInitializer接口的所有类型
*/
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
    
    @Override
    public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
            throws ServletException {
        //1 创建存储WebApplicationInitializer的List
        List<WebApplicationInitializer> initializers = new LinkedList<>();
        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 {
                        //2 用反射机制创建WebApplicationInitializer实现类并且添加到List中
                        initializers.add((WebApplicationInitializer)
                                ReflectionUtils.accessibleConstructor(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;
        }
        servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
        AnnotationAwareOrderComparator.sort(initializers);
        //3 调用WebApplicationInitializerde的onStartup方法
        for (WebApplicationInitializer initializer : initializers) {
            initializer.onStartup(servletContext);
        }
    }
}

(2)WebApplicationInitializer接口实现类分析 AbstractContextLoaderInitializer
在这里插入图片描述

(3) WebApplicationInitializer接口实现类分析 AbstractDispatcherServletInitializer
在这里插入图片描述

(4) WebApplicationInitializer接口实现类分析 AbstractAnnotationConfigDispatcherServletInitializer

public abstract class AbstractAnnotationConfigDispatcherServletInitializer
        extends AbstractDispatcherServletInitializer {
    /**
     * 创建RootApplicationContext
     */
    @Override
    @Nullable
    protected WebApplicationContext createRootApplicationContext() {
        Class<?>[] configClasses = getRootConfigClasses();
        if (!ObjectUtils.isEmpty(configClasses)) {
            AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
            context.register(configClasses);
            return context;
        }
        else {
            return null;
        }
    }
    /**
     * 创建ServletApplicationContext
     */
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        Class<?>[] configClasses = getServletConfigClasses();
        if (!ObjectUtils.isEmpty(configClasses)) {
            context.register(configClasses);
        }
        return context;
    }
    /**
     * 获取RootApplicationContext 配置类
     */
    @Nullable
    protected abstract Class<?>[] getRootConfigClasses();
    /**
     * 获取ServletApplicationContext配置类
     */
    @Nullable
    protected abstract Class<?>[] getServletConfigClasses();
}

(5) ServletApplicationContext和RootApplicationContext区别如下图:
ServletApplicationContext:负责Controller 视图相关的…
RootApplicationContext:负责Service、数据库相关的…
在这里插入图片描述

发布了146 篇原创文章 · 获赞 76 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/qq_34125999/article/details/104688149
今日推荐