疑问:为什么实现了WebApplicationInitializer接口的类,在自动时会自动执行其重写的onStart()方法?
第一步: 查看接口WebApplicationInitializer的API(spring-web-x.x.x.jar下),该接口只有一个方法:
void onStartup(ServletContext servletContext) throws ServletException;
接口说明:
Interface to be implemented in Servlet 3.0+ environments in order to configure the ServletContext programmatically – as opposed to (or possibly in conjunction with) the traditional web.xml-based approach.
Implementations of this SPI will be detected automatically by SpringServletContainerInitializer, which itself is bootstrapped automatically by any Servlet 3.0 container.
翻译过来,实现该接口可以在Servlet 3.0 +环境中以编程方式配置ServletContext,而不是(或结合)传统的基于web.xml文件配置。实现由SpringServletContainerInitializer SPI将自动检测到,这本身就是由任何Servlet 3.0容器自动引导。
第二步:查看类SpringServletContainerInitializer的API(同包下),该类实现了ServletContainerInitializer接口,重写了其void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException;
方法
其方法代码如下:
@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);
}
}
类说明:
This class will be loaded and instantiated and have its onStartup(java.util.Set, javax.servlet.ServletContext) method invoked by any Servlet 3.0-compliant container during container startup assuming that the spring-web module JAR is present on the classpath. This occurs through the JAR Services API ServiceLoader.load(Class) method detecting the spring-web module’s META-INF/services/javax.servlet.ServletContainerInitializer service provider configuration file. See the JAR Services API documentation as well as section 8.2.4 of the Servlet 3.0 Final Draft specification for complete details.
翻译过来,这个类将被加载和实例化,其 onStartup(java.util.Set<java.lang.Class<?>>, javax.servlet.ServletContext)方法在任何Servlet 3.0兼容的容器在容器启动时被调用,当JAR的spring-web模块存在的classpath中。在当JAR服务API
ServiceLoader.load(Class)方法检测spring-web模块的
META-INF/services/javax.servlet.ServletContainerInitializer`服务提供者配置文件时发生。请参见JAR服务API文档以及部分8.2.4 Servlet 3.0的最终草案规范完整的细节。