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、数据库相关的…