先看下servlet注入到tomcat服务器的过程,
DispatcherServletAutoConfiguration$DispatcherServletConfiguration
类中声明了Bean方法,会创建DispatcherServlet类型的Bean,然后作为dispatcherServletRegistration方法的参数注入到DispatcherServletRegistrationBean内部。
java"> @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {DispatcherServlet dispatcherServlet = new DispatcherServlet();dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());return dispatcherServlet;}@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,webMvcProperties.getServlet().getPath());registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());multipartConfig.ifAvailable(registration::setMultipartConfig);return registration;}
创建web服务器时this.webServer = factory.getWebServer(getSelfInitializer());
,会返回指向selfInitialize()
方法的引用赋值给函数式接口ServletContextInitializer.
java"> private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {return this::selfInitialize;}private void selfInitialize(ServletContext servletContext) throws ServletException {prepareWebApplicationContext(servletContext);registerApplicationScope(servletContext);WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);for (ServletContextInitializer beans : getServletContextInitializerBeans()) {beans.onStartup(servletContext);}}
在TomcatServletWebServerFactory#prepareContext()
中,使用TomcatStarter类封装刚才注入的ServletContextInitializer接口,添加到Context容器的private Map<ServletContainerInitializer,Set<Class<?>>> initializers = new LinkedHashMap<>();
中。
java"> protected void prepareContext(Host host, ServletContextInitializer[] initializers) {......context.addLifecycleListener(new StaticResourceConfigurer(context));ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);host.addChild(context);configureContext(context, initializersToUse);postProcessContext(context);}protected void configureContext(Context context, ServletContextInitializer[] initializers) {TomcatStarter starter = new TomcatStarter(initializers);if (context instanceof TomcatEmbeddedContext) {TomcatEmbeddedContext embeddedContext = (TomcatEmbeddedContext) context;embeddedContext.setStarter(starter);embeddedContext.setFailCtxIfServletStartFails(true);}context.addServletContainerInitializer(starter, NO_CLASSES);
......}
初始化完成后就会进入tomcat服务器的启动流程,此时会遍历内部的initializers,调用每个ServletContainerInitializer接口的onStartup()方法。
java">protected synchronized void startInternal() throws LifecycleException {......for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :initializers.entrySet()) {try {entry.getKey().onStartup(entry.getValue(),getServletContext());} catch (ServletException e) {log.error(sm.getString("standardContext.sciFail"), e);ok = false;break;}}......
}
此时会遍历TomcatStarter内部的initializers。
java"> public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {try {for (ServletContextInitializer initializer : this.initializers) {initializer.onStartup(servletContext);}}......}
TomcatStarter内部的private final ServletContextInitializer[] initializers
会包含selfInitialize方法的lamb引用,即会调用selfInitialize方法。
java"> private void selfInitialize(ServletContext servletContext) throws ServletException {prepareWebApplicationContext(servletContext);registerApplicationScope(servletContext);WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);for (ServletContextInitializer beans : getServletContextInitializerBeans()) {beans.onStartup(servletContext);}}protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {return new ServletContextInitializerBeans(getBeanFactory());}public ServletContextInitializerBeans(ListableBeanFactory beanFactory,Class<? extends ServletContextInitializer>... initializerTypes) {this.initializers = new LinkedMultiValueMap<>();//默认为 ServletContextInitializer 类型this.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes): Collections.singletonList(ServletContextInitializer.class);addServletContextInitializerBeans(beanFactory);addAdaptableBeans(beanFactory);List<ServletContextInitializer> sortedInitializers = this.initializers.values().stream().flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE)).collect(Collectors.toList());this.sortedList = Collections.unmodifiableList(sortedInitializers);logMappings(this.initializers);}// 取出ServletContextInitializer类型bean//添加到private final MultiValueMap<Class<?>, ServletContextInitializer> initializers;private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {for (Class<? extends ServletContextInitializer> initializerType : this.initializerTypes) {for (Entry<String, ? extends ServletContextInitializer> initializerBean : getOrderedBeansOfType(beanFactory,initializerType)) {addServletContextInitializerBean(initializerBean.getKey(), initializerBean.getValue(), beanFactory);}}}
由于ServletContextInitializerBeans实现了Iterable迭代器接口,可以对此对象进行迭代,而我们之前创建的
DispatcherServletRegistrationBean实现了ServletContextInitializer接口,因此会调用父类RegistrationBean
的onStartup
方法,最终在ApplicationContext#addServlet()
方法中生成Wrapper对象,添加到StandardContext容器中。
java"> private ServletRegistration.Dynamic addServlet(String servletName, String servletClass,Servlet servlet, Map<String,String> initParams) throws IllegalStateException {if (servletName == null || servletName.equals("")) {throw new IllegalArgumentException(sm.getString("applicationContext.invalidServletName", servletName));}if (!context.getState().equals(LifecycleState.STARTING_PREP)) {//TODO Spec breaking enhancement to ignore this restrictionthrow new IllegalStateException(sm.getString("applicationContext.addServlet.ise",getContextPath()));}Wrapper wrapper = (Wrapper) context.findChild(servletName);// Assume a 'complete' ServletRegistration is one that has a class and// a nameif (wrapper == null) {wrapper = context.createWrapper();wrapper.setName(servletName);context.addChild(wrapper);} else {if (wrapper.getName() != null &&wrapper.getServletClass() != null) {if (wrapper.isOverridable()) {wrapper.setOverridable(false);} else {return null;}}}ServletSecurity annotation = null;if (servlet == null) {wrapper.setServletClass(servletClass);Class<?> clazz = Introspection.loadClass(context, servletClass);if (clazz != null) {annotation = clazz.getAnnotation(ServletSecurity.class);}} else {wrapper.setServletClass(servlet.getClass().getName());wrapper.setServlet(servlet);if (context.wasCreatedDynamicServlet(servlet)) {annotation = servlet.getClass().getAnnotation(ServletSecurity.class);}}if (initParams != null) {for (Map.Entry<String, String> initParam: initParams.entrySet()) {wrapper.addInitParameter(initParam.getKey(), initParam.getValue());}}ServletRegistration.Dynamic registration =new ApplicationServletRegistration(wrapper, context);if (annotation != null) {registration.setServletSecurity(new ServletSecurityElement(annotation));}return registration;}
到tomcat服务器调用子容器的startInternal
方法阶段会注册到Context容器,
java"> private void registerContext(Context context) {String contextPath = context.getPath();if ("/".equals(contextPath)) {contextPath = "";}Host host = (Host)context.getParent();WebResourceRoot resources = context.getResources();String[] welcomeFiles = context.findWelcomeFiles();List<WrapperMappingInfo> wrappers = new ArrayList<>();for (Container container : context.findChildren()) {prepareWrapperMappingInfo(context, (Wrapper) container, wrappers);if(log.isDebugEnabled()) {log.debug(sm.getString("mapperListener.registerWrapper",container.getName(), contextPath, service));}}mapper.addContextVersion(host.getName(), host, contextPath,context.getWebappVersion(), context, welcomeFiles, resources,wrappers);if(log.isDebugEnabled()) {log.debug(sm.getString("mapperListener.registerContext",contextPath, service));}}
最终在Mapper#addWrapper()
方法中赋值给public MappedWrapper defaultWrapper
,而处理请求时默认会使用defaultWrapper处理请求,就是说spring内置的DispatcherServlet是默认的servlet,所以请求默认都会被DispatcherServlet分发到内部的mvc的Controller中。