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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。