spring web
源码
@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 { 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); } } }
WebApplicationInitializer 有4个实现类
1. AbstractContextLoaderInitializer
public abstract class AbstractContextLoaderInitializer implements WebApplicationInitializer { /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); @Override public void onStartup(ServletContext servletContext) throws ServletException { registerContextLoaderListener(servletContext); //注册 监听器 } /** * Register a {@link ContextLoaderListener} against the given servlet context. The * {@code ContextLoaderListener} is initialized with the application context returned * from the {@link #createRootApplicationContext()} template method. * @param servletContext the servlet context to register the listener against */ protected void registerContextLoaderListener(ServletContext servletContext) { WebApplicationContext rootAppContext = createRootApplicationContext(); //创建web根容器 if (rootAppContext != null) { ContextLoaderListener listener = new ContextLoaderListener(rootAppContext); listener.setContextInitializers(getRootApplicationContextInitializers()); servletContext.addListener(listener); //添加监听器 } else { logger.debug("No ContextLoaderListener registered, as " + "createRootApplicationContext() did not return an application context"); } } /** * Create the "<strong>root</strong>" application context to be provided to the * {@code ContextLoaderListener}. * <p>The returned context is delegated to * {@link ContextLoaderListener#ContextLoaderListener(WebApplicationContext)} and will * be established as the parent context for any {@code DispatcherServlet} application * contexts. As such, it typically contains middle-tier services, data sources, etc. * @return the root application context, or {@code null} if a root context is not * desired * @see org.springframework.web.servlet.support.AbstractDispatcherServletInitializer */ @Nullable protected abstract WebApplicationContext createRootApplicationContext(); /** * Specify application context initializers to be applied to the root application * context that the {@code ContextLoaderListener} is being created with. * @since 4.2 * @see #createRootApplicationContext() * @see ContextLoaderListener#setContextInitializers */ @Nullable protected ApplicationContextInitializer<?>[] getRootApplicationContextInitializers() { return null; } }
2 . AbstractDispatcherServletInitializer
public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer { public static final String DEFAULT_SERVLET_NAME = "dispatcher"; public AbstractDispatcherServletInitializer() { } public void onStartup(ServletContext servletContext) throws ServletException { super.onStartup(servletContext); this.registerDispatcherServlet(servletContext); } protected void registerDispatcherServlet(ServletContext servletContext) { String servletName = this.getServletName(); Assert.hasLength(servletName, "getServletName() must not return null or empty"); WebApplicationContext servletAppContext = this.createServletApplicationContext(); Assert.notNull(servletAppContext, "createServletApplicationContext() must not return null"); FrameworkServlet dispatcherServlet = this.createDispatcherServlet(servletAppContext); Assert.notNull(dispatcherServlet, "createDispatcherServlet(WebApplicationContext) must not return null"); dispatcherServlet.setContextInitializers(this.getServletApplicationContextInitializers()); Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet); //添加servlet if (registration == null) { throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. Check if there is another servlet registered under the same name."); } else { registration.setLoadOnStartup(1); registration.addMapping(this.getServletMappings()); //添加mapping registration.setAsyncSupported(this.isAsyncSupported()); Filter[] filters = this.getServletFilters(); if (!ObjectUtils.isEmpty(filters)) { Filter[] var7 = filters; int var8 = filters.length; for(int var9 = 0; var9 < var8; ++var9) { Filter filter = var7[var9]; this.registerServletFilter(servletContext, filter); } } this.customizeRegistration(registration); } } protected String getServletName() { return "dispatcher"; } protected abstract WebApplicationContext createServletApplicationContext(); protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) { return new DispatcherServlet(servletAppContext); } @Nullable protected ApplicationContextInitializer<?>[] getServletApplicationContextInitializers() { return null; } protected abstract String[] getServletMappings(); @Nullable protected Filter[] getServletFilters() { return null; } protected javax.servlet.FilterRegistration.Dynamic registerServletFilter(ServletContext servletContext, Filter filter) { String filterName = Conventions.getVariableName(filter); javax.servlet.FilterRegistration.Dynamic registration = servletContext.addFilter(filterName, filter); if (registration == null) { for(int counter = 0; registration == null; ++counter) { if (counter == 100) { throw new IllegalStateException("Failed to register filter with name '" + filterName + "'. Check if there is another filter registered under the same name."); } registration = servletContext.addFilter(filterName + "#" + counter, filter); //添加filter } } registration.setAsyncSupported(this.isAsyncSupported()); registration.addMappingForServletNames(this.getDispatcherTypes(), false, new String[]{this.getServletName()}); return registration; } private EnumSet<DispatcherType> getDispatcherTypes() { return this.isAsyncSupported() ? EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ASYNC) : EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE); } protected boolean isAsyncSupported() { return true; } protected void customizeRegistration(Dynamic registration) { } }
3 AbstractAnnotationConfigDispatcherServletInitializer
public abstract class AbstractAnnotationConfigDispatcherServletInitializer extends AbstractDispatcherServletInitializer { public AbstractAnnotationConfigDispatcherServletInitializer() { } @Nullable protected WebApplicationContext createRootApplicationContext() { Class<?>[] configClasses = this.getRootConfigClasses(); if (!ObjectUtils.isEmpty(configClasses)) { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); //类似spring 中配置文件 context.register(configClasses); return context; } else { return null; } } protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); Class<?>[] configClasses = this.getServletConfigClasses(); if (!ObjectUtils.isEmpty(configClasses)) { context.register(configClasses); } return context; } @Nullable protected abstract Class<?>[] getRootConfigClasses(); @Nullable protected abstract Class<?>[] getServletConfigClasses(); }
public abstract class AbstractContextLoaderInitializer implements WebApplicationInitializer { /** Logger available to subclasses */protected final Log logger = LogFactory.getLog(getClass());@Overridepublic void onStartup(ServletContext servletContext) throws ServletException { registerContextLoaderListener(servletContext);} /** * Register a {@link ContextLoaderListener} against the given servlet context. The * {@code ContextLoaderListener} is initialized with the application context returned * from the {@link #createRootApplicationContext()} template method. * @param servletContext the servlet context to register the listener against */protected void registerContextLoaderListener(ServletContext servletContext) { WebApplicationContext rootAppContext = createRootApplicationContext(); if (rootAppContext != null) { ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);listener.setContextInitializers(getRootApplicationContextInitializers());servletContext.addListener(listener);} else { logger.debug("No ContextLoaderListener registered, as " + "createRootApplicationContext() did not return an application context");} } /** * Create the "<strong>root</strong>" application context to be provided to the * {@code ContextLoaderListener}. * <p>The returned context is delegated to * {@link ContextLoaderListener#ContextLoaderListener(WebApplicationContext)} and will * be established as the parent context for any {@code DispatcherServlet} application * contexts. As such, it typically contains middle-tier services, data sources, etc. * @return the root application context, or {@code null} if a root context is not * desired * @see org.springframework.web.servlet.support.AbstractDispatcherServletInitializer */@Nullableprotected abstract WebApplicationContext createRootApplicationContext();/** * Specify application context initializers to be applied to the root application * context that the {@code ContextLoaderListener} is being created with. * @since 4.2 * @see #createRootApplicationContext() * @see ContextLoaderListener#setContextInitializers */@Nullableprotected ApplicationContextInitializer<?>[] getRootApplicationContextInitializers() { return null;}}