SpringBoot如何实现Tomcat自动配置
目录
准备工作
我们知道SpringBoot的自动装配的秘密在org.springframework.boot.autoconfigure包下的spring.factories文件中,而嵌入Tomcat的原理就在这个文件中加载的一个配置类:org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
@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}) publicclassServletWebServerFactoryAutoConfiguration{ @Bean publicServletWebServerFactoryCustomizerservletWebServerFactoryCustomizer( ServerPropertiesserverProperties){ returnnewServletWebServerFactoryCustomizer(serverProperties); } @Bean @ConditionalOnClass(name="org.apache.catalina.startup.Tomcat") publicTomcatServletWebServerFactoryCustomizertomcatServletWebServerFactoryCustomizer( ServerPropertiesserverProperties){ returnnewTomcatServletWebServerFactoryCustomizer(serverProperties); } /** *Registersa{@linkWebServerFactoryCustomizerBeanPostProcessor}.Registeredvia *{@linkImportBeanDefinitionRegistrar}forearlyregistration. */ publicstaticclassBeanPostProcessorsRegistrar implementsImportBeanDefinitionRegistrar,BeanFactoryAware{ privateConfigurableListableBeanFactorybeanFactory; @Override publicvoidsetBeanFactory(BeanFactorybeanFactory)throwsBeansException{ if(beanFactoryinstanceofConfigurableListableBeanFactory){ this.beanFactory=(ConfigurableListableBeanFactory)beanFactory; } } @Override publicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata, BeanDefinitionRegistryregistry){ if(this.beanFactory==null){ return; } registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor", WebServerFactoryCustomizerBeanPostProcessor.class); registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor", ErrorPageRegistrarBeanPostProcessor.class); } privatevoidregisterSyntheticBeanIfMissing(BeanDefinitionRegistryregistry, Stringname,Class>beanClass){ if(ObjectUtils.isEmpty( this.beanFactory.getBeanNamesForType(beanClass,true,false))){ RootBeanDefinitionbeanDefinition=newRootBeanDefinition(beanClass); beanDefinition.setSynthetic(true); registry.registerBeanDefinition(name,beanDefinition); } } } }
首先看一下上方的几个注解
- @AutoConfigureOrder这个注解是决定配置类的加载顺序的,当注解里的值越小越先加载,而Ordered.HIGHEST_PRECEDENCE的值是Integer.MIN_VALUE也就是说这个类肯定是最先加载的那一批
- @ConditionalOnXXX在之前的文章中已经无数次提到了,就不再阐述了
- @EnableConfigurationProperties开启ServerProperties类的属性值配置。而这个类里面包含的就是Web服务的配置
@ConfigurationProperties(prefix="server",ignoreUnknownFields=true) publicclassServerProperties{ privateIntegerport; privateInetAddressaddress; @NestedConfigurationProperty privatefinalErrorPropertieserror=newErrorProperties(); privateBooleanuseForwardHeaders; privateStringserverHeader; privateintmaxHttpHeaderSize=0;//bytes privateDurationconnectionTimeout; @NestedConfigurationProperty privateSslssl; @NestedConfigurationProperty privatefinalCompressioncompression=newCompression(); @NestedConfigurationProperty privatefinalHttp2http2=newHttp2(); privatefinalServletservlet=newServlet(); privatefinalTomcattomcat=newTomcat(); privatefinalJettyjetty=newJetty(); privatefinalUndertowundertow=newUndertow(); }
这个类的代码太多了,这里就不一一贴出来了,我们平常在application.properties中配置的server.xxx就是这个类中属性
@Import BeanPostProcessorsRegistrar publicstaticclassBeanPostProcessorsRegistrar implementsImportBeanDefinitionRegistrar,BeanFactoryAware{ @Override publicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata, BeanDefinitionRegistryregistry){ if(this.beanFactory==null){ return; } registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor", WebServerFactoryCustomizerBeanPostProcessor.class); registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor", ErrorPageRegistrarBeanPostProcessor.class); } privatevoidregisterSyntheticBeanIfMissing(BeanDefinitionRegistryregistry, Stringname,Class>beanClass){ if(ObjectUtils.isEmpty( this.beanFactory.getBeanNamesForType(beanClass,true,false))){ RootBeanDefinitionbeanDefinition=newRootBeanDefinition(beanClass); beanDefinition.setSynthetic(true); registry.registerBeanDefinition(name,beanDefinition); } } }
这个类注册了两个bean:WebServerFactoryCustomizerBeanPostProcessor和ErrorPageRegistrarBeanPostProcessor关于这两个bean的作用稍后再详细介绍
- EmbeddedTomcat
@Configuration @ConditionalOnClass({Servlet.class,Tomcat.class,UpgradeProtocol.class}) @ConditionalOnMissingBean(value=ServletWebServerFactory.class,search=SearchStrategy.CURRENT) publicstaticclassEmbeddedTomcat{ @Bean publicTomcatServletWebServerFactorytomcatServletWebServerFactory(){ returnnewTomcatServletWebServerFactory(); } }
这个类会在存在Tomcat相关jar包时添加一个TomcatServletWebServerFactorybean
其他两个相信大家都知道怎么回事了
除了这些这个类还注入了两个类ServletWebServerFactoryCustomizer和TomcatServletWebServerFactoryCustomizer
现在前期准备工作已经做好了,看一下这个Tomcat是如何启动的吧
启动
启动入口在ServletWebServerApplicationContext中的onRefresh方法
protectedvoidonRefresh(){ super.onRefresh(); try{ createWebServer(); } catch(Throwableex){ thrownewApplicationContextException("Unabletostartwebserver",ex); } }
Tomcat的启动就在createWebServer方法里面了
privatevoidcreateWebServer(){ WebServerwebServer=this.webServer; ServletContextservletContext=getServletContext(); //第一次访问的时候两个对象都为空 if(webServer==null&&servletContext==null){ ServletWebServerFactoryfactory=getWebServerFactory(); this.webServer=factory.getWebServer(getSelfInitializer()); } elseif(servletContext!=null){ try{ getSelfInitializer().onStartup(servletContext); } catch(ServletExceptionex){ thrownewApplicationContextException("Cannotinitializeservletcontext", ex); } } initPropertySources(); }
首先看一下getWebServerFactory
protectedServletWebServerFactorygetWebServerFactory(){ //这里获取的beanname就是上方注册的tomcatServletWebServerFactory了 String[]beanNames=getBeanFactory() .getBeanNamesForType(ServletWebServerFactory.class); if(beanNames.length==0){ thrownewApplicationContextException( "UnabletostartServletWebServerApplicationContextduetomissing" +"ServletWebServerFactorybean."); } if(beanNames.length>1){ thrownewApplicationContextException( "UnabletostartServletWebServerApplicationContextduetomultiple" +"ServletWebServerFactorybeans:" +StringUtils.arrayToCommaDelimitedString(beanNames)); } returngetBeanFactory().getBean(beanNames[0],ServletWebServerFactory.class); }
准备环境里注册的bean现在出来一个了。注意,上方还注册了一个后置处理器EmbeddedServletContainerCustomizerBeanPostProcessor,获取beantomcatServletWebServerFactory的时候就会执行后置处理器的postProcessBeforeInitialization方法
publicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName) throwsBeansException{ if(beaninstanceofWebServerFactory){ postProcessBeforeInitialization((WebServerFactory)bean); } returnbean; } privatevoidpostProcessBeforeInitialization(WebServerFactorywebServerFactory){ LambdaSafe .callbacks(WebServerFactoryCustomizer.class,getCustomizers(), webServerFactory) .withLogger(WebServerFactoryCustomizerBeanPostProcessor.class) .invoke((customizer)->customizer.customize(webServerFactory)); } privateCollection>getCustomizers(){ if(this.customizers==null){ //Lookupdoesnotincludetheparentcontext this.customizers=newArrayList<>(getWebServerFactoryCustomizerBeans()); this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE); this.customizers=Collections.unmodifiableList(this.customizers); } returnthis.customizers; } @SuppressWarnings({"unchecked","rawtypes"}) privateCollection >getWebServerFactoryCustomizerBeans(){ return(Collection)this.beanFactory .getBeansOfType(WebServerFactoryCustomizer.class,false,false).values(); }
这个处理器的作用是获得所有定制器,然后执行定制器的方法
接着往下看
这个时候就可以启动Tomcat了
publicWebServergetWebServer(ServletContextInitializer...initializers){ Tomcattomcat=newTomcat(); FilebaseDir=(this.baseDirectory!=null?this.baseDirectory :createTempDir("tomcat")); tomcat.setBaseDir(baseDir.getAbsolutePath()); Connectorconnector=newConnector(this.protocol); tomcat.getService().addConnector(connector); customizeConnector(connector); tomcat.setConnector(connector); tomcat.getHost().setAutoDeploy(false); configureEngine(tomcat.getEngine()); for(ConnectoradditionalConnector:this.additionalTomcatConnectors){ tomcat.getService().addConnector(additionalConnector); } prepareContext(tomcat.getHost(),initializers); returngetTomcatWebServer(tomcat); } protectedTomcatWebServergetTomcatWebServer(Tomcattomcat){ returnnewTomcatWebServer(tomcat,getPort()>=0); } publicTomcatWebServer(Tomcattomcat,booleanautoStart){ Assert.notNull(tomcat,"TomcatServermustnotbenull"); this.tomcat=tomcat; this.autoStart=autoStart; initialize(); } privatevoidinitialize()throwsWebServerException{ TomcatWebServer.logger.info("Tomcatinitializedwithport(s):"+getPortsDescription(false)); synchronized(this.monitor){ try{ addInstanceIdToEngineName(); Contextcontext=findContext(); context.addLifecycleListener((event)->{ if(context.equals(event.getSource()) &&Lifecycle.START_EVENT.equals(event.getType())){ //Removeserviceconnectorssothatprotocolbindingdoesn't //happenwhentheserviceisstarted. removeServiceConnectors(); } }); //Starttheservertotriggerinitializationlisteners this.tomcat.start(); //Wecanre-throwfailureexceptiondirectlyinthemainthread rethrowDeferredStartupExceptions(); try{ ContextBindings.bindClassLoader(context,context.getNamingToken(), getClass().getClassLoader()); } catch(NamingExceptionex){ //Namingisnotenabled.Continue } //UnlikeJetty,allTomcatthreadsaredaemonthreads.Wecreatea //blockingnon-daemontostopimmediateshutdown startDaemonAwaitThread(); } catch(Exceptionex){ thrownewWebServerException("UnabletostartembeddedTomcat",ex); } } }
以上就是SpringBoot如何实现Tomcat自动配置的详细内容,更多关于SpringBoot实现Tomcat自动配置的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。