servlet 3.0 規範
角色:應用方(spring) + servlet + web容器(tomcat)
servlet 3.0 規範
- 規範提供ServletContainerInitializer接口,應用方提供實現類。
- 規範提供"根目錄/resources/META-INF/services/javax.servlet.ServletContainerInitializer"路徑,應用方把ServletContainerInitializer接口實現類全類名寫在該文件內。
- 規範提供@HandlesTypes註解,由應用方配置,web容器解析,解析得到的實現類集合將通過參數傳給ServletContainerInitializer.onStartup方法。
- web容器啓動完成回調ServletContainerInitializer.onStartup方法。
spring-web 如何實現servlet規範
spring提供WebApplicationInitializer接口,讓程序員方便地進行web容器初始化回調。
spring把WebApplicationInitializer接口配置到@HandlesTypes,讓web容器找到所有WebApplicationInitializer接口的實現類。
spring提供SpringServletContainerInitializer類實現ServletContainerInitializer接口,把web容器找到的實現類實例化出來,並執行。
spring把SpringServletContainerInitializer全類名配置到servlet規定的文件內,由web容器調用。
WebApplicationInitializer
public interface WebApplicationInitializer {
void onStartup(ServletContext servletContext) throws ServletException;
}
SpringServletContainerInitializer
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
// webAppInitializerClasses:web容器找到的WebApplicationInitializer的實現類集合
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
// 執行集合
List<WebApplicationInitializer> initializers = new LinkedList<>();
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
// 驗證 添加到執行集合
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
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);
for (WebApplicationInitializer initializer : initializers) {
// 遍歷執行
initializer.onStartup(servletContext);
}
}
}
/resources/META-INF/services/javax.servlet.ServletContainerInitializer
org.springframework.web.SpringServletContainerInitializer
自己實現servlet 3.0 規範
CustomWebApplicationInitializer
// 參考spring的WebApplicationInitializer接口
public interface CustomWebApplicationInitializer {
void onStartup(ServletContext servletContext) throws ServletException;
}
CustomServletContainerInitializer
// 提供ServletContainerInitializer接口實現類,加上@HandlesTypes註解,傳入自己提供的CustomWebApplicationInitializer接口
@HandlesTypes(CustomWebApplicationInitializer.class)
public class CustomServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
List<CustomWebApplicationInitializer> initializers = new LinkedList<>();
if (c != null) {
for (Class<?> waiClass : c) {
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && CustomWebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((CustomWebApplicationInitializer) ReflectionUtils.accessibleConstructor(waiClass).newInstance());
} catch (Throwable ex) {
throw new ServletException("Failed to instantiate CustomWebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
ctx.log("No Spring CustomWebApplicationInitializer types detected on classpath");
return;
}
ctx.log(initializers.size() + " Spring CustomWebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
for (CustomWebApplicationInitializer initializer : initializers) {
initializer.onStartup(ctx);
}
}
}
/resources/META-INF/services/javax.servlet.ServletContainerInitializer
com.tbryant.springmvctest.customspringmvc.core.CustomServletContainerInitializer
使用自己實現servlet 3.0 規範
MyCustomWebApplicationInitializer
public class MyCustomWebApplicationInitializer implements CustomWebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
System.out.println("web容器初始化回調,可在此添加spring容器啓動代碼");
}
}
其他類文件請參考spring 零xml配置 & 內置tomcat 啓動spring mvc