說在前面web
本次主要介紹springmvc配置解析,關注「天河聊架構」微信公衆號更多源碼解析文章。spring
springmvc配置解析微信
sdervlet容器啓動的時候會加載org.springframework.web.SpringServletContainerInitializer這個類,調用初始化類的onStartup方法架構
@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; } servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath"); AnnotationAwareOrderComparator.sort(initializers); for (WebApplicationInitializer initializer : initializers) { initializer.onStartup(servletContext); } }
進入到DispatcherServlet初始化器 org.springframework.web.servlet.support.AbstractDispatcherServletInitializer#onStartup這個方法mvc
@Override public void onStartup(ServletContext servletContext) throws ServletException { //調用上下文加載器初始化類的onStartup方法 super.onStartup(servletContext); //註冊DispatcherServlet registerDispatcherServlet(servletContext); }
進入到這個方法org.springframework.web.context.AbstractContextLoaderInitializer#onStartup,執行ContextLoader初始化器app
@Override public void onStartup(ServletContext servletContext) throws ServletException { registerContextLoaderListener(servletContext); }
進入到這個方法org.springframework.web.context.AbstractContextLoaderInitializer#registerContextLoaderListener,註冊ContextLoader監聽器異步
protected void registerContextLoaderListener(ServletContext servletContext) { // 獲取上層應用上下文對象 -> WebApplicationContext rootAppContext = createRootApplicationContext(); if (rootAppContext != null) { // 建立上下文加載監聽器 ContextLoaderListener listener = new ContextLoaderListener(rootAppContext); listener.setContextInitializers(getRootApplicationContextInitializers()); // 把上下文加載監聽器加載到servlet容器 servletContext.addListener(listener); } else { logger.debug("No ContextLoaderListener registered, as " + "createRootApplicationContext() did not return an application context"); } }
進入到這個方法org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer#createRootApplicationContextide
@Override protected WebApplicationContext createRootApplicationContext() { //從子類實現中或者從@Configuration、@Component註解配置中獲取配置類 Class<?>[] configClasses = getRootConfigClasses(); if (!ObjectUtils.isEmpty(configClasses)) { // 若是沒有配置就默認初始化基於註解的web應用上下文類 AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext(); rootAppContext.register(configClasses); return rootAppContext; } else { return null; } }
進入到這個方法org.springframework.web.context.AbstractContextLoaderInitializer#getRootApplicationContextInitializersspa
protected ApplicationContextInitializer<?>[] getRootApplicationContextInitializers() { return null; }
返回到這個方法org.springframework.web.servlet.support.AbstractDispatcherServletInitializer#onStartup這一行debug
// 註冊DispatcherServlet registerDispatcherServlet(servletContext);
進入到這個方法org.springframework.web.servlet.support.AbstractDispatcherServletInitializer#registerDispatcherServlet
protected void registerDispatcherServlet(ServletContext servletContext) { //獲取servletName,默認名稱是dispatcher String servletName = getServletName(); Assert.hasLength(servletName, "getServletName() must not return empty or null"); //建立servlet程序上下文 -> WebApplicationContext servletAppContext = createServletApplicationContext(); Assert.notNull(servletAppContext, "createServletApplicationContext() did not return an application " + "context for servlet [" + servletName + "]"); //建立DispatcherServlet FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext); //註冊servlet上下文初始化器,這裏是模板實現 dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers()); //添加DispatcherServlet到servlet容器 ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet); Assert.notNull(registration, "Failed to register servlet with name '" + servletName + "'." + "Check if there is another servlet registered under the same name."); registration.setLoadOnStartup(1); //獲取servletMapping實現,這裏是抽象實現,註冊mapping registration.addMapping(getServletMappings()); //設置是否支持異步,默認支持 registration.setAsyncSupported(isAsyncSupported()); //獲取servletFilter,這裏是模板實現 Filter[] filters = getServletFilters(); if (!ObjectUtils.isEmpty(filters)) { for (Filter filter : filters) { //註冊filter -> registerServletFilter(servletContext, filter); } } //定製化註冊,默認是模板實現 customizeRegistration(registration); }
進入到這個方法org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer#createServletApplicationContext
@Override protected WebApplicationContext createServletApplicationContext() { //建立基於註解的web應用上下文 AnnotationConfigWebApplicationContext servletAppContext = new AnnotationConfigWebApplicationContext(); //從子類實現中或者從@Configuration、@Component註解配置中獲取配置類 Class<?>[] configClasses = getServletConfigClasses(); if (!ObjectUtils.isEmpty(configClasses)) { // 註冊@Configuration配置的配置加載類到AnnotationConfigWebApplicationContext servletAppContext.register(configClasses); } return servletAppContext; }
進入到這個方法org.springframework.web.servlet.support.AbstractDispatcherServletInitializer#registerServletFilter
protected FilterRegistration.Dynamic registerServletFilter(ServletContext servletContext, Filter filter) { //獲取filteName String filterName = Conventions.getVariableName(filter); //添加filter到servlet容器 Dynamic registration = servletContext.addFilter(filterName, filter); //若是filter註冊失敗 if (registration == null) { int counter = -1; while (counter == -1 || registration == null) { counter++; //添加filter#0 到servlet容器 registration = servletContext.addFilter(filterName + "#" + counter, filter); //提示有一樣的名字的filter已註冊過 Assert.isTrue(counter < 100, "Failed to register filter '" + filter + "'." + "Could the same Filter instance have been registered already?"); } } //是否支持異步,默認是 registration.setAsyncSupported(isAsyncSupported()); registration.addMappingForServletNames(getDispatcherTypes(), false, getServletName()); return registration; }
回退到這個方法org.springframework.web.SpringServletContainerInitializer#onStartup
說到最後
本次源碼解析僅表明我的觀點,僅供參考。