一、如何定制和修改Servlet容器的相关配置
1)修改server有关的配置(ServerProperties)
server.port=8081 server.context‐path=/crud server.tomcat.uri‐encoding=UTF‐8
2)EmbeddedServletContainerCustomizer
@Bean //一定要将这个定制器加入到容器中 public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){ return new EmbeddedServletContainerCustomizer() { //定制嵌入式的Servlet容器相关的规则 @Override public void customize(ConfigurableEmbeddedServletContainer container) { container.setPort(8081); } }; }
ServerProperties、EmbeddedServletContainerCustomizer定制器怎么就帮我们修改了Servlet容器的配置呢
容器中导入了EmbeddedServletContainerCustomizerBeanPostProcessor
spring创建对象,填充属性之前,执行applyBeanPostProcessorsBeforeInitialization
1 @Override 2 public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) 3 throws BeansException { 4 5 Object result = existingBean; 6 for (BeanPostProcessor processor : getBeanPostProcessors()) { 7 result = processor.postProcessBeforeInitialization(result, beanName); 8 if (result == null) { 9 return result; 10 } 11 } 12 return result; 13 }
1 public class EmbeddedServletContainerCustomizerBeanPostProcessor 2 implements BeanPostProcessor, BeanFactoryAware { 3 4 private ListableBeanFactory beanFactory; 5 6 private List<EmbeddedServletContainerCustomizer> customizers; 7 8 9 @Override 10 public Object postProcessBeforeInitialization(Object bean, String beanName) 11 throws BeansException { 12 if (bean instanceof ConfigurableEmbeddedServletContainer) {//如果当前初始化的是一个ConfigurableEmbeddedServletContainer类型的组件 13 postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean); 14 } 15 return bean; 16 } 17 18 private void postProcessBeforeInitialization( 19 ConfigurableEmbeddedServletContainer bean) { 20 for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {//获取所有的定制器,调用每一个定制器的customize方法来给Servlet容器进行属性赋值; 21 customizer.customize(bean); 22 } 23 } 24 25 private Collection<EmbeddedServletContainerCustomizer> getCustomizers() { 26 if (this.customizers == null) { 27 // Look up does not include the parent context 28 this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(//从容器中获取所有这葛类型的组件:EmbeddedServletContainerCustomizer 29 this.beanFactory 30 .getBeansOfType(EmbeddedServletContainerCustomizer.class, 31 false, false) 32 .values()); 33 Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE); 34 this.customizers = Collections.unmodifiableList(this.customizers); 35 } 36 return this.customizers; 37 }
ServerProperties
1 @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) 2 public class ServerProperties 3 implements EmbeddedServletContainerCustomizer, EnvironmentAware, Ordered { 4 5 @Override 6 public void customize(ConfigurableEmbeddedServletContainer container) { 7 if (getPort() != null) { 8 container.setPort(getPort()); 9 } 10 if (getAddress() != null) { 11 container.setAddress(getAddress()); 12 } 13 if (getContextPath() != null) { 14 container.setContextPath(getContextPath()); 15 } 16 if (getDisplayName() != null) { 17 container.setDisplayName(getDisplayName()); ......
2)注册Servlet三大组件【Servlet、Filter、Listener】
ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean
1 @Bean 2 public ServletRegistrationBean myServlet(){ 3 return new ServletRegistrationBean(new MyServlet(),"/myServlet"); 4 }
3)嵌入式Servlet容器自动配置原理--EmbeddedServletContainerAutoConfiguration
1 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) 2 @Configuration 3 @ConditionalOnWebApplication 4 @Import(BeanPostProcessorsRegistrar.class) 5 public class EmbeddedServletContainerAutoConfiguration { 6 7 /** 8 * Nested configuration if Tomcat is being used. 9 */ 10 @Configuration 11 @ConditionalOnClass({ Servlet.class, Tomcat.class }) 12 @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT) 13 public static class EmbeddedTomcat { 14 15 @Bean 16 public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() { 17 return new TomcatEmbeddedServletContainerFactory(); 18 } 19 20 } 21 22 /** 23 * Nested configuration if Jetty is being used. 24 */ 25 @Configuration 26 @ConditionalOnClass({ Servlet.class, Server.class, Loader.class, 27 WebAppContext.class }) 28 @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT) 29 public static class EmbeddedJetty { 30 31 @Bean 32 public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() { 33 return new JettyEmbeddedServletContainerFactory(); 34 } 35 36 } 37 38 /** 39 * Nested configuration if Undertow is being used. 40 */ 41 @Configuration 42 @ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class }) 43 @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT) 44 public static class EmbeddedUndertow { 45 46 @Bean 47 public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory() { 48 return new UndertowEmbeddedServletContainerFactory(); 49 } 50 51 }
EmbeddedServletContainerFactory(嵌入式Servlet容器工厂)
EmbeddedServletContainer:(嵌入式的Servlet容器)
以TomcatEmbeddedServletContainerFactory为例
1 public EmbeddedServletContainer getEmbeddedServletContainer( 2 ServletContextInitializer... initializers) { 3 Tomcat tomcat = new Tomcat(); 4 File baseDir = (this.baseDirectory != null) ? this.baseDirectory 5 : createTempDir("tomcat"); 6 tomcat.setBaseDir(baseDir.getAbsolutePath()); 7 Connector connector = new Connector(this.protocol); 8 tomcat.getService().addConnector(connector); 9 customizeConnector(connector); 10 tomcat.setConnector(connector); 11 tomcat.getHost().setAutoDeploy(false); 12 configureEngine(tomcat.getEngine()); 13 for (Connector additionalConnector : this.additionalTomcatConnectors) { 14 tomcat.getService().addConnector(additionalConnector); 15 } 16 prepareContext(tomcat.getHost(), initializers); 17 return getTomcatEmbeddedServletContainer(tomcat);//将配置好的Tomcat传入进去,返回一个EmbeddedServletContainer;并且启动Tomcat服务器 18 }
4)嵌入式Servlet容器启动原理
1、SpringBoot应用启动运行run方法
2、refreshContext(context);SpringBoot刷新IOC容器【创建IOC容器对象,并初始化容器,创建容器中的每一
个组件】;如果是web应用创建AnnotationConfigEmbeddedWebApplicationContext,否则:
AnnotationConfigApplicationContext
3、refresh(context);刷新刚才创建好的ioc容器;
1 @Override 2 public void refresh() throws BeansException, IllegalStateException { 3 synchronized (this.startupShutdownMonitor) { 4 // Prepare this context for refreshing. 5 prepareRefresh(); 6 7 // Tell the subclass to refresh the internal bean factory. 8 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 9 10 // Prepare the bean factory for use in this context. 11 prepareBeanFactory(beanFactory); 12 13 try { 14 // Allows post-processing of the bean factory in context subclasses. 15 postProcessBeanFactory(beanFactory); 16 17 // Invoke factory processors registered as beans in the context. 18 invokeBeanFactoryPostProcessors(beanFactory); 19 20 // Register bean processors that intercept bean creation. 21 registerBeanPostProcessors(beanFactory); 22 23 // Initialize message source for this context. 24 initMessageSource(); 25 26 // Initialize event multicaster for this context. 27 initApplicationEventMulticaster(); 28 29 // Initialize other special beans in specific context subclasses. 30 onRefresh(); 31 32 // Check for listener beans and register them. 33 registerListeners(); 34 35 // Instantiate all remaining (non-lazy-init) singletons. 36 finishBeanFactoryInitialization(beanFactory); 37 38 // Last step: publish corresponding event. 39 finishRefresh(); 40 } 41 42 catch (BeansException ex) { 43 if (logger.isWarnEnabled()) { 44 logger.warn("Exception encountered during context initialization - " + 45 "cancelling refresh attempt: " + ex); 46 } 47 48 // Destroy already created singletons to avoid dangling resources. 49 destroyBeans(); 50 51 // Reset 'active' flag. 52 cancelRefresh(ex); 53 54 // Propagate exception to caller. 55 throw ex; 56 } 57 58 finally { 59 // Reset common introspection caches in Spring's core, since we 60 // might not ever need metadata for singleton beans anymore... 61 resetCommonCaches(); 62 } 63 } 64 }
4、AnnotationConfigEmbeddedWebApplicationContext重写该onRefresh()。
protected void onRefresh() { super.onRefresh(); try { createEmbeddedServletContainer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start embedded container", ex); } } private void createEmbeddedServletContainer() { EmbeddedServletContainer localContainer = this.embeddedServletContainer; ServletContext localServletContext = getServletContext(); if (localContainer == null && localServletContext == null) { EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory(); this.embeddedServletContainer = containerFactory .getEmbeddedServletContainer(getSelfInitializer()); } else if (localServletContext != null) { try { getSelfInitializer().onStartup(localServletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } } initPropertySources(); }