[A] source SpringMVC ServletContainerInitializer && SpringMVC source ingress parsing

1 ServletContainerInitializer

When web container starts to third-party components to provide the opportunity to do some initialization work, ServletContainerInitializer implement this feature servlet specification (JSR356) by. Each frame you want to use ServletContainerInitializer you must create a file named javax.servlet.ServletContainerInitializer in the corresponding jar package META-INF / services directory, file content to assign specific ServletContainerInitializer implementation class, then it will start when the web container run the initialization is done some initial work in the components.

(1) Create a JAVA-WEB project
Here Insert Picture Description
(2) create the interface and interface related classes

public interface ZrsService {

}

public interface ZrsServiceExtend extends ZrsService {

}

public abstract class AbstractZrsService implements ZrsService {

}

public class ZrsServicImpl implements ZrsService {

}

(3) create ServletContainerInitializer interface class

/**
* @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) create javax.servlet.ServletContainerInitializer in the META-INF / services

com.servlet.ZrsServletContainerInitializer

(5) engineering structures
Here Insert Picture Description
(6) to start tomcat, found a method called ZrsServletContainerInitializer onStartup
Here Insert Picture Description

2 SpringMVC environment ready

(1) create a maven project
Here Insert Picture Description

(2) Delete all * .xml files in the webapp
Here Insert Picture Description
(3) introduced dependence

<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 View spring-web package
Here Insert Picture Description

4 Preliminary analysis SpringServletContainerInitializer

(1) source code analysis, initialization WebApplicationInitializer bean interface and call methods WebApplicationInitializer implementation class 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 interface class analysis AbstractContextLoaderInitializer
Here Insert Picture Description

(3) WebApplicationInitializer interface class analysis AbstractDispatcherServletInitializer
Here Insert Picture Description

(4) WebApplicationInitializer interface class analysis 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 and RootApplicationContext difference in the following figure:
ServletApplicationContext: Controller is responsible for the relevant view ...
RootApplicationContext: responsible for Service, database-related ...
Here Insert Picture Description

Published 146 original articles · won praise 76 · views 80000 +

Guess you like

Origin blog.csdn.net/qq_34125999/article/details/104688149