SpringBoot
中内置了 Servlet
容器,支持 Tomcat
, Jetty
和 Undertow
服务器,所以可以直接运行。相比之下,传统的JavaWeb
程序则需要嵌入到Tomcat
之类的 Servlet
容器中才能运行。接下来就来学习一下, SpringBoot
加载内置的 Servlet
容器的流程。
一、相关类介绍 WebServer
SpringBoot
对内置的 Servlet
容器做了一层封装
1 2 3 4 5 6 7 8 9 10 public interface WebServer { void start () throws WebServerException ; void stop () throws WebServerException ; int getPort () ; }
它目前有下图中五个实现类,对应了四种容器 Jetty
、 Tomcat
、 UnderTow
、 Netty
,其中 Netty
不是 Servlet
容器。
ServletWebServerFactory
ServletWebServerFactory
是一个工厂接口,用来生产 WebServer
。
1 2 3 4 5 @FunctionalInterface public interface ServletWebServerFactory { WebServer getWebServer (ServletContextInitializer... initializers) ; }
ServletContextInitializer
ServletContextInitializer
是 Servlet初始化器 ,用于配置 ServletContext
,在调用 getWebServer()
方法创建 Servlet内置容器 的时候会调用它的 onStartup()
方法,getWebServer()
方法何时调用会在后续讲 Servlet 容器的创建和启动时讲到。
1 2 3 4 public interface ServletContextInitializer { void onStartup (ServletContext servletContext) throws ServletException ; }
ServletWebServerFactoryAutoConfiguration
下面我们来看看 ServletWebServerFactory
是怎么被注册到Spring容器中的。找到 ServletWebServerFactoryAutoConfiguration.class
,这个类是 Servlet 容器的自动配置类,可以在 spring.factories
中找到这个类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 @Configuration @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @ConditionalOnClass(ServletRequest.class) @ConditionalOnWebApplication(type = Type.SERVLET) @EnableConfigurationProperties(ServerProperties.class) @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, ServletWebServerFactoryConfiguration.EmbeddedTomcat.class, ServletWebServerFactoryConfiguration.EmbeddedJetty.class, ServletWebServerFactoryConfiguration.EmbeddedUndertow.class }) public class ServletWebServerFactoryAutoConfiguration { @Bean public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer (ServerProperties serverProperties) { return new ServletWebServerFactoryCustomizer(serverProperties); } @Bean @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat") public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer ( ServerProperties serverProperties) { return new TomcatServletWebServerFactoryCustomizer(serverProperties); } public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar , BeanFactoryAware { private ConfigurableListableBeanFactory beanFactory; @Override public void setBeanFactory (BeanFactory beanFactory) throws BeansException { if (beanFactory instanceof ConfigurableListableBeanFactory) { this .beanFactory = (ConfigurableListableBeanFactory) beanFactory; } } @Override public void registerBeanDefinitions (AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { if (this .beanFactory == null ) { return ; } registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor" , WebServerFactoryCustomizerBeanPostProcessor.class); registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor" , ErrorPageRegistrarBeanPostProcessor.class); } private void registerSyntheticBeanIfMissing (BeanDefinitionRegistry registry, String name, Class<?> beanClass) { if (ObjectUtils.isEmpty(this .beanFactory.getBeanNamesForType(beanClass, true , false ))) { RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); beanDefinition.setSynthetic(true ); registry.registerBeanDefinition(name, beanDefinition); } } } }
可以看到上面的自动配置类中导入了三个 ServletWebServerFactoryConfiguration
的内部类,ServletWebServerFactory
的注册就是在这儿完成的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 @Configuration class ServletWebServerFactoryConfiguration { @Configuration @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class }) @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) public static class EmbeddedTomcat { @Bean public TomcatServletWebServerFactory tomcatServletWebServerFactory () { return new TomcatServletWebServerFactory(); } } @Configuration @ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class }) @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) public static class EmbeddedJetty { @Bean public JettyServletWebServerFactory JettyServletWebServerFactory () { return new JettyServletWebServerFactory(); } } @Configuration @ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class }) @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) public static class EmbeddedUndertow { @Bean public UndertowServletWebServerFactory undertowServletWebServerFactory () { return new UndertowServletWebServerFactory(); } } }
WebServerFactoryCustomizerBeanPostProcessor
WebServerFactoryCustomizerBeanPostProcessor
是一个 BeanPostProcessor
,它在 postProcessBeforeInitialization
过程中去寻找 Spring 容器中 WebServerFactoryCustomizer
类型的Bean,并依次调用这个接口的 customize()
方法对内置容器工厂做一些定制化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Override public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException { if (bean instanceof WebServerFactory) { postProcessBeforeInitialization((WebServerFactory) bean); } return bean; } private void postProcessBeforeInitialization (WebServerFactory webServerFactory) { LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory) .withLogger(WebServerFactoryCustomizerBeanPostProcessor.class) .invoke((customizer) -> customizer.customize(webServerFactory)); } private Collection<WebServerFactoryCustomizer<?>> getCustomizers() { if (this .customizers == null ) { this .customizers = new ArrayList<>(getWebServerFactoryCustomizerBeans()); this .customizers.sort(AnnotationAwareOrderComparator.INSTANCE); this .customizers = Collections.unmodifiableList(this .customizers); } return this .customizers; } private Collection<WebServerFactoryCustomizer<?>> getWebServerFactoryCustomizerBeans() { return (Collection) this .beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false , false ).values(); }
WebServerFactoryCustomizer
这个类主要作用就是对内置的容器工厂进行一些定制化处理,比如设置端口,地址,错误页面等
1 2 3 4 5 @FunctionalInterface public interface WebServerFactoryCustomizer <T extends WebServerFactory > { void customize (T factory) ; }
OK,到这为止,主要的涉及到加载 内置Servlet容器 的类都介绍完了,下面就以 tomcat
为例来看看内置 Servlet
的创建和启动流程。
二、Servlet的创建 回到之前看的 SpringBoot
启动代码上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 public ConfigurableApplicationContext run (String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null ; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this .logStartupInfo) { new StartupInfoLogger(this .mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null ); throw new IllegalStateException(ex); } return context; }
容器的创建 重点看一下第三步—创建Spring容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 protected ConfigurableApplicationContext createApplicationContext () { Class<?> contextClass = this .applicationContextClass; if (contextClass == null ) { try { switch (this .webApplicationType) { case SERVLET: contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS); break ; case REACTIVE: contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break ; default : contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass" , ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }
根据 webApplicationType
判断当前服务的类型,然后创建对应的 Spring
容器,以 web
程序为例,这里就会执行
1 contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
对应的类是AnnotationConfigServletWebServerApplicationContext
,因此最终创建的容器就是AnnotationConfigServletWebServerApplicationContext
容器的配置 再来看一下第五步—刷新容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private void refreshContext (ConfigurableApplicationContext context) { refresh(context); if (this .registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException ex) { } } } protected void refresh (ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext) applicationContext).refresh(); }
进到 refresh()
方法中看一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 public void refresh () throws BeansException, IllegalStateException { synchronized (this .startupShutdownMonitor) { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } }
看一下 onRefresh()
这个方法
1 2 3 protected void onRefresh () throws BeansException { }
是个空方法,但是使用了 protected
进行修饰,也就是子类可以重写这个方法,那我们去子类看一下具体的实现,进到 ServletWebServerApplicationContext
这个类中,这个类是我们之前创建的Spring容器 AnnotationConfigServletWebServerApplicationContext
的父类。这个类实现了onRefresh()
方法,在其中完成了对内置Servlet容器的获取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 protected void onRefresh () { super .onRefresh(); try { createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server" , ex); } } private void createWebServer () { WebServer webServer = this .webServer; ServletContext servletContext = getServletContext(); if (webServer == null && servletContext == null ) { ServletWebServerFactory factory = getWebServerFactory(); this .webServer = factory.getWebServer(getSelfInitializer()); } else if (servletContext != null ) { try { getSelfInitializer().onStartup(servletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context" , ex); } } initPropertySources(); }
getWebServerFactory()
,获取内置容器工厂,上面我们讲过三种内置 Servlet
工厂的注册过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 protected ServletWebServerFactory getWebServerFactory () { String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class); if (beanNames.length == 0 ) { throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing " + "ServletWebServerFactory bean." ); } if (beanNames.length > 1 ) { throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple " + "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames)); } return getBeanFactory().getBean(beanNames[0 ], ServletWebServerFactory.class); }
再来看一下 getSelfInitializer()
这个方法,这是一个函数式接口,它主要就是获取 Servlet初始化器 ,这个初始化器内部会构造一个ServletContextInitializerBeans
(Servlet初始化器—ServletContextInitializer的集合 ),ServletContextInitializerBeans
构造时会去 Spring 容器中寻找 ServletContextInitializer
类型的bean,其中 ServletRegistrationBean
、FilterRegistrationBean
、ServletListenerRegistrationBean
会被找出(如果有定义)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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); } }
getServletContextInitializerBeans()
方法
1 2 3 4 protected Collection<ServletContextInitializer> getServletContextInitializerBeans () { return new ServletContextInitializerBeans(getBeanFactory()); }
ServletContextInitializerBeans
对象是对ServletContextInitializer
的一种包装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class ServletContextInitializerBeans extends AbstractCollection <ServletContextInitializer > { private final MultiValueMap<Class<?>, ServletContextInitializer> initializers; private final List<Class<? extends ServletContextInitializer>> initializerTypes; private List<ServletContextInitializer> sortedList; public ServletContextInitializerBeans (ListableBeanFactory beanFactory, Class<? extends ServletContextInitializer>... initializerTypes) { this .initializers = new LinkedMultiValueMap<>(); 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); } }
addServletContextInitializerBeans()
方法,在这里获取所有ServletContextInitializer
类型的 bean
,并存放到initializers
中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 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); } } } private void addServletContextInitializerBean (String beanName, ServletContextInitializer initializer, ListableBeanFactory beanFactory) { if (initializer instanceof ServletRegistrationBean) { Servlet source = ((ServletRegistrationBean<?>) initializer).getServlet(); addServletContextInitializerBean(Servlet.class, beanName, initializer, beanFactory, source); } else if (initializer instanceof FilterRegistrationBean) { Filter source = ((FilterRegistrationBean<?>) initializer).getFilter(); addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source); } else if (initializer instanceof DelegatingFilterProxyRegistrationBean) { String source = ((DelegatingFilterProxyRegistrationBean) initializer).getTargetBeanName(); addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source); } else if (initializer instanceof ServletListenerRegistrationBean) { EventListener source = ((ServletListenerRegistrationBean<?>) initializer).getListener(); addServletContextInitializerBean(EventListener.class, beanName, initializer, beanFactory, source); } else { addServletContextInitializerBean(ServletContextInitializer.class, beanName, initializer, beanFactory, initializer); } } private void addServletContextInitializerBean (Class<?> type, String beanName, ServletContextInitializer initializer, ListableBeanFactory beanFactory, Object source) { this .initializers.add(type, initializer); if (source != null ) { this .seen.add(source); } if (logger.isTraceEnabled()) { String resourceDescription = getResourceDescription(beanName, beanFactory); int order = getOrder(initializer); logger.trace("Added existing " + type.getSimpleName() + " initializer bean '" + beanName + "'; order=" + order + ", resource=" + resourceDescription); } }
这些 ServletContextInitializer
类型的 bean
例如 ServletRegistrationBean.class
,通过 SpringBoot
的 AutoConfiguration
装配到 Spring
容器 中,在注册时会将对应的 Servlet
添加到自己的参数中,我们以 DispatchServletRegistrationBean
为例来看一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @Configuration @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass(DispatcherServlet.class) @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) public class DispatcherServletAutoConfiguration { public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet" ; public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration" ; @Configuration @Conditional(DefaultDispatcherServletCondition.class) @ConditionalOnClass(ServletRegistration.class) @EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class }) protected static class DispatcherServletConfiguration { private final HttpProperties httpProperties; private final WebMvcProperties webMvcProperties; public DispatcherServletConfiguration (HttpProperties httpProperties, WebMvcProperties webMvcProperties) { this .httpProperties = httpProperties; this .webMvcProperties = webMvcProperties; } @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet () { DispatcherServlet dispatcherServlet = new DispatcherServlet(); dispatcherServlet.setDispatchOptionsRequest(this .webMvcProperties.isDispatchOptionsRequest()); dispatcherServlet.setDispatchTraceRequest(this .webMvcProperties.isDispatchTraceRequest()); dispatcherServlet .setThrowExceptionIfNoHandlerFound(this .webMvcProperties.isThrowExceptionIfNoHandlerFound()); dispatcherServlet.setEnableLoggingRequestDetails(this .httpProperties.isLogRequestDetails()); return dispatcherServlet; } @Bean @ConditionalOnBean(MultipartResolver.class) @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) public MultipartResolver multipartResolver (MultipartResolver resolver) { return resolver; } } @Configuration @Conditional(DispatcherServletRegistrationCondition.class) @ConditionalOnClass(ServletRegistration.class) @EnableConfigurationProperties(WebMvcProperties.class) @Import(DispatcherServletConfiguration.class) protected static class DispatcherServletRegistrationConfiguration { private final WebMvcProperties webMvcProperties; private final MultipartConfigElement multipartConfig; public DispatcherServletRegistrationConfiguration (WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfigProvider) { this .webMvcProperties = webMvcProperties; this .multipartConfig = multipartConfigProvider.getIfAvailable(); } @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME) @ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServletRegistrationBean dispatcherServletRegistration (DispatcherServlet dispatcherServlet) { DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet, this .webMvcProperties.getServlet().getPath()); registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME); registration.setLoadOnStartup(this .webMvcProperties.getServlet().getLoadOnStartup()); if (this .multipartConfig != null ) { registration.setMultipartConfig(this .multipartConfig); } return registration; } } }
这些ServletContextInitializer
类型的Bean
注册到Spring容器之后,在addServletContextInitializerBeans()
方法中就会被获取到并存放到initializers
集合中。
再来看看另一个方法addAdaptableBeans(beanFactory)
,与上面的方法不同,这个是直接获取Servlet.class
和Filter.class
类型的Bean
,并通过对应的adapter
将其构建为RegistrationBean
对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 protected void addAdaptableBeans (ListableBeanFactory beanFactory) { MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory); addAsRegistrationBean(beanFactory, Servlet.class, new ServletRegistrationBeanAdapter(multipartConfig)); addAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter()); for (Class<?> listenerType : ServletListenerRegistrationBean.getSupportedTypes()) { addAsRegistrationBean(beanFactory, EventListener.class, (Class<EventListener>) listenerType, new ServletListenerRegistrationBeanAdapter()); } } protected <T> void addAsRegistrationBean (ListableBeanFactory beanFactory, Class<T> type, RegistrationBeanAdapter<T> adapter) { addAsRegistrationBean(beanFactory, type, type, adapter); } private <T, B extends T> void addAsRegistrationBean (ListableBeanFactory beanFactory, Class<T> type, Class<B> beanType, RegistrationBeanAdapter<T> adapter) { List<Map.Entry<String, B>> entries = getOrderedBeansOfType(beanFactory, beanType, this .seen); for (Entry<String, B> entry : entries) { String beanName = entry.getKey(); B bean = entry.getValue(); if (this .seen.add(bean)) { RegistrationBean registration = adapter.createRegistrationBean(beanName, bean, entries.size()); int order = getOrder(bean); registration.setOrder(order); this .initializers.add(type, registration); if (logger.isTraceEnabled()) { logger.trace("Created " + type.getSimpleName() + " initializer for bean '" + beanName + "'; order=" + order + ", resource=" + getResourceDescription(beanName, beanFactory)); } } } }
通过 ServletRegistrationBeanAdapter
和 FilterRegistrationBeanAdapter
将 Servlet.class
和 Fliter.class
封装成ServletRegistrationBean
对象和FilterRegistrationBean
对象,这与前通过AutoConfiguration
自动装配的RegistrationBean
是一样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 private static class ServletRegistrationBeanAdapter implements RegistrationBeanAdapter <Servlet > { private final MultipartConfigElement multipartConfig; ServletRegistrationBeanAdapter(MultipartConfigElement multipartConfig) { this .multipartConfig = multipartConfig; } @Override public RegistrationBean createRegistrationBean (String name, Servlet source, int totalNumberOfSourceBeans) { String url = (totalNumberOfSourceBeans != 1 ) ? "/" + name + "/" : "/" ; if (name.equals(DISPATCHER_SERVLET_NAME)) { url = "/" ; } ServletRegistrationBean<Servlet> bean = new ServletRegistrationBean<>(source, url); bean.setName(name); bean.setMultipartConfig(this .multipartConfig); return bean; } } private static class FilterRegistrationBeanAdapter implements RegistrationBeanAdapter <Filter > { @Override public RegistrationBean createRegistrationBean (String name, Filter source, int totalNumberOfSourceBeans) { FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>(source); bean.setName(name); return bean; } }
下面这些 Bean
就是通过上面两个方法获取到的 ServletContextInitializer
类型的实例
获取到了所有 ServletContextInitializer
类型的 Bean
之后,就该调用它们的 onStartUp()
方法了,下面就以 ServletRegistrationBean
为例来看一下这个方法,先来看一下类关系图
当调用 ServletContextInitializer
的 onStartUp()
方法时,首先进入到RegistrationBean
类中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public abstract class RegistrationBean implements ServletContextInitializer , Ordered { @Override public final void onStartup (ServletContext servletContext) throws ServletException { String description = getDescription(); if (!isEnabled()) { logger.info(StringUtils.capitalize(description) + " was not registered (disabled)" ); return ; } register(description, servletContext); } } protected abstract void register (String description, ServletContext servletContext) ;
接着看RegistrationBean
的子类DynamicRegistrationBean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public abstract class DynamicRegistrationBean <D extends Registration .Dynamic > extends RegistrationBean { @Override protected final void register (String description, ServletContext servletContext) { D registration = addRegistration(description, servletContext); if (registration == null ) { logger.info( StringUtils.capitalize(description) + " was not registered " + "(possibly already registered?)" ); return ; } configure(registration); } }
最后再看DynamicRegistrationBean
的子类ServletRegistrationBean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 protected String getDescription () { Assert.notNull(this .servlet, "Servlet must not be null" ); return "servlet " + getServletName(); } protected ServletRegistration.Dynamic addRegistration (String description, ServletContext servletContext) { String name = getServletName(); return servletContext.addServlet(name, this .servlet); } protected void configure (ServletRegistration.Dynamic registration) { super .configure(registration); String[] urlMapping = StringUtils.toStringArray(this .urlMappings); if (urlMapping.length == 0 && this .alwaysMapUrl) { urlMapping = DEFAULT_MAPPINGS; } if (!ObjectUtils.isEmpty(urlMapping)) { registration.addMapping(urlMapping); } registration.setLoadOnStartup(this .loadOnStartup); if (this .multipartConfig != null ) { registration.setMultipartConfig(this .multipartConfig); } }
进行完以上 onStartUp()
方法后,Servlet
就被加入到Tomcat
中了,这样我们就能发送请求给这个Servlet
了。
Filter
的配置流程同上,将Filter
通过addFilter()
加入到Tomcat
中之后,Filter
就能进行请求拦截了。
1 2 3 4 protected Dynamic addRegistration (String description, ServletContext servletContext) { Filter filter = getFilter(); return servletContext.addFilter(getOrDeduceName(filter), filter); }
三、Servlet的启动 Servlet
容器创建完毕之后在 finishRefresh()
方法中会被启动,让我们回到 ServletWebServerApplicationContext.class
中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Override protected void finishRefresh () { super .finishRefresh(); WebServer webServer = startWebServer(); if (webServer != null ) { publishEvent(new ServletWebServerInitializedEvent(webServer, this )); } } private WebServer startWebServer () { WebServer webServer = this .webServer; if (webServer != null ) { webServer.start(); } return webServer; }
到此为止,内置的 Servlet
容器就完成了创建和启动的流程。