SpringMVC的IOC容器的初始化
1.引导spring应用加载
首先,Servlet3.0的Web应用服务器中,例如Tomcat7或更高版本,服务器会在启动的时候在类路径下查找javax.servlet.ServletContainerInitializer接口的实现类(利用SPI原理),引导spring应用启动。执行实现WebApplicationInitializer类的onStartup方法
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
/**
* Delegate the {@code ServletContext} to any {@link WebApplicationInitializer}
* implementations present on the application classpath.
* <p>Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)},
* Servlet 3.0+ containers will automatically scan the classpath for implementations
* of Spring's {@code WebApplicationInitializer} interface and provide the set of all
* such types to the {@code webAppInitializerClasses} parameter of this method.
* <p>If no {@code WebApplicationInitializer} implementations are found on the classpath,
* this method is effectively a no-op. An INFO-level log message will be issued notifying
* the user that the {@code ServletContainerInitializer} has indeed been invoked but that
* no {@code WebApplicationInitializer} implementations were found.
* <p>Assuming that one or more {@code WebApplicationInitializer} types are detected,
* they will be instantiated (and <em>sorted</em> if the @{@link
* org.springframework.core.annotation.Order @Order} annotation is present or
* the {@link org.springframework.core.Ordered Ordered} interface has been
* implemented). Then the {@link WebApplicationInitializer#onStartup(ServletContext)}
* method will be invoked on each instance, delegating the {@code ServletContext} such
* that each instance may register and configure servlets such as Spring's
* {@code DispatcherServlet}, listeners such as Spring's {@code ContextLoaderListener},
* or any other Servlet API componentry such as filters.
* @param webAppInitializerClasses all implementations of
* {@link WebApplicationInitializer} found on the application classpath
* @param servletContext the servlet context to be initialized
* @see WebApplicationInitializer#onStartup(ServletContext)
* @see AnnotationAwareOrderComparator
*
*/
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
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 {
//实例化WebApplicationInitializer子类
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);
}
}
}
可以看到onStartup方法有两个参数,Set webAppInitializerClasses 和 ServletContext ctx。
- 如果ServletContainerInitializer接口的实现类使用@HandlesTypes注解声明了感兴趣的类或接口,那么这个感兴趣的类及其子类或接口的实现类就会被设置到webAppInitializerClasses参数中。
- ServletContext是一个全局的储存信息的空间,服务器开始就存在,服务器关闭才释放。由服务器创建
webAppInitializerClasses 中包括了WebApplicationInitializer类所有的子类。但是在代码中只有实体类才会进行处理并调用
排序后进行实例化
2.WebApplicationInitializer子类的实例化
WebApplicationInitializer类的作用用于配置Servlet容器,例如注册Servlet、Filter或Listener以取代以取代通过web.xml
配置注册。这样就利于开发内聚的web应用框架.
WebApplicationInitializer下有两个子类分别为AbstractContextLoaderInitializer和AbstractDispatcherServletInitializer前者用于根容器的加载。后者用于子容器的加载。
看AbstractDispatcherServletInitializer#onStartup的实现
public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer {
/**
* The default servlet name. Can be customized by overriding {@link #getServletName}.
*/
public static final String DEFAULT_SERVLET_NAME = "dispatcher";
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
//注册ContextLoaderListener监听器,让它去初始化Spring父容器
super.onStartup(servletContext);
//注册DispatcherServlet,让它去初始化Spring MVC的子容器
registerDispatcherServlet(servletContext);
}
}
3.父容器的加载
super的onStartup主要负责父容器的初始化
@Override
public void onStartup(ServletContext servletContext) throws ServletException {