springboot 基于Tomcat容器的自启动流程分析
Springboot内置了Tomcat的容器,我们今天来说一下Springboot的自启动流程。
一、Spring通过注解导入Bean大体可分为四种方式,我们主要来说以下Import的两种实现方法:
1、通过实现ImportSerlector接口,实现Bean加载:
publicclassTestServiceImpl{
publicvoidtestImpl(){
System.out.println("我是通过importSelector导入进来的service");
}
}
publicclassTestServiceimplementsImportSelector{
@Override
publicString[]selectImports(AnnotationMetadataannotationMetadata){
returnnewString[]{"com.ycdhz.service.TestServiceImpl"};
}
}
@Configuration
@Import(value={TestService.class})
publicclassTestConfig{
}
publicclassTestController{
@Autowired
privateTestServiceImpltestServiceImpl;
@RequestMapping("testImpl")
publicStringtestTuling(){
testServiceImpl.testImpl();
return"Ok";
}
}
2、通过实现ImportSerlector接口,实现Bean加载:
publicclassTestService{
publicTestService(){
System.out.println("我是通过ImportBeanDefinitionRegistrar导入进来的组件");
}
}
publicclassTestImportBeanDefinitionRegistrarimplementsImportBeanDefinitionRegistrar{
@Override
publicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata,BeanDefinitionRegistryregistry){
//定义一个BeanDefinition
RootBeanDefinitionbeanDefinition=newRootBeanDefinition(TestService.class);
//把自定义的bean定义导入到容器中
registry.registerBeanDefinition("testService",beanDefinition);
}
}
@Configuration
@Import(TestImportBeanDefinitionRegistrar.class)
publicclassTestConfig{
}
二、Springboot启动过程中会自动装配
我们从spring-boot-autoconfigure-2.0.6.RELEASE.jar下搜索到Tomcat的相关配置,发现有两个自动装配类,分别包含了三个定制器(面向对象的单一职责原则),还有一个工厂类。
2.1、TomcatWebServerFactoryCustomizer:定制Servlet和Reactive服务器通用的Tomcat特定功能。
publicclassTomcatWebServerFactoryCustomizerimplements WebServerFactoryCustomizer,Ordered{ @Override publicvoidcustomize(ConfigurableTomcatWebServerFactoryfactory){ ServerPropertiesproperties=this.serverProperties; ServerProperties.TomcattomcatProperties=properties.getTomcat(); PropertyMapperpropertyMapper=PropertyMapper.get(); propertyMapper.from(tomcatProperties::getBasedir).whenNonNull() .to(factory::setBaseDirectory); propertyMapper.from(tomcatProperties::getBackgroundProcessorDelay).whenNonNull() .as(Duration::getSeconds).as(Long::intValue) .to(factory::setBackgroundProcessorDelay); customizeRemoteIpValve(factory); propertyMapper.from(tomcatProperties::getMaxThreads).when(this::isPositive) .to((maxThreads)->customizeMaxThreads(factory, tomcatProperties.getMaxThreads())); propertyMapper.from(tomcatProperties::getMinSpareThreads).when(this::isPositive) .to((minSpareThreads)->customizeMinThreads(factory,minSpareThreads)); propertyMapper.from(()->determineMaxHttpHeaderSize()).when(this::isPositive) .to((maxHttpHeaderSize)->customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize)); propertyMapper.from(tomcatProperties::getMaxHttpPostSize) .when((maxHttpPostSize)->maxHttpPostSize!=0) .to((maxHttpPostSize)->customizeMaxHttpPostSize(factory, maxHttpPostSize)); propertyMapper.from(tomcatProperties::getAccesslog) .when(ServerProperties.Tomcat.Accesslog::isEnabled) .to((enabled)->customizeAccessLog(factory)); propertyMapper.from(tomcatProperties::getUriEncoding).whenNonNull() .to(factory::setUriEncoding); propertyMapper.from(properties::getConnectionTimeout).whenNonNull() .to((connectionTimeout)->customizeConnectionTimeout(factory, connectionTimeout)); propertyMapper.from(tomcatProperties::getMaxConnections).when(this::isPositive) .to((maxConnections)->customizeMaxConnections(factory,maxConnections)); propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive) .to((acceptCount)->customizeAcceptCount(factory,acceptCount)); customizeStaticResources(factory); customizeErrorReportValve(properties.getError(),factory); } }
2.2、ServletWebServerFactoryCustomizer:WebServerFactoryCustomizer将ServerProperties属性应用于Tomcatweb服务器。
publicclassServletWebServerFactoryCustomizerimplements WebServerFactoryCustomizer,Ordered{ privatefinalServerPropertiesserverProperties; publicServletWebServerFactoryCustomizer(ServerPropertiesserverProperties){ this.serverProperties=serverProperties; } @Override publicintgetOrder(){ return0; } @Override publicvoidcustomize(ConfigurableServletWebServerFactoryfactory){ PropertyMappermap=PropertyMapper.get().alwaysApplyingWhenNonNull(); map.from(this.serverProperties::getPort).to(factory::setPort); map.from(this.serverProperties::getAddress).to(factory::setAddress); map.from(this.serverProperties.getServlet()::getContextPath) .to(factory::setContextPath); map.from(this.serverProperties.getServlet()::getApplicationDisplayName) .to(factory::setDisplayName); map.from(this.serverProperties.getServlet()::getSession).to(factory::setSession); map.from(this.serverProperties::getSsl).to(factory::setSsl); map.from(this.serverProperties.getServlet()::getJsp).to(factory::setJsp); map.from(this.serverProperties::getCompression).to(factory::setCompression); map.from(this.serverProperties::getHttp2).to(factory::setHttp2); map.from(this.serverProperties::getServerHeader).to(factory::setServerHeader); map.from(this.serverProperties.getServlet()::getContextParameters) .to(factory::setInitParameters); } }
2.3、ServletWebServerFactoryCustomizer:WebServerFactoryCustomizer将ServerProperties属性应用于Tomcatweb服务器。
publicclassTomcatServletWebServerFactoryCustomizer implementsWebServerFactoryCustomizer,Ordered{ privatefinalServerPropertiesserverProperties; publicTomcatServletWebServerFactoryCustomizer(ServerPropertiesserverProperties){ this.serverProperties=serverProperties; } @Override publicvoidcustomize(TomcatServletWebServerFactoryfactory){ ServerProperties.TomcattomcatProperties=this.serverProperties.getTomcat(); if(!ObjectUtils.isEmpty(tomcatProperties.getAdditionalTldSkipPatterns())){ factory.getTldSkipPatterns() .addAll(tomcatProperties.getAdditionalTldSkipPatterns()); } if(tomcatProperties.getRedirectContextRoot()!=null){ customizeRedirectContextRoot(factory, tomcatProperties.getRedirectContextRoot()); } if(tomcatProperties.getUseRelativeRedirects()!=null){ customizeUseRelativeRedirects(factory, tomcatProperties.getUseRelativeRedirects()); } } }
三、有了TomcatServletWebServerFactory,相当于有了Spring加载的入口
通过AbstractApplicationContext#onReFresh()在IOC容器中的带动tomcat启动,然后在接着执行ioc容器的其他步骤。
我们通过断点可以观察Tomcat加载的整个生命周期,以及三个定制器的加载过程。
@Override
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);
//创建Tomcat引擎
configureEngine(tomcat.getEngine());
for(ConnectoradditionalConnector:this.additionalTomcatConnectors){
tomcat.getService().addConnector(additionalConnector);
}
//刷新上下文
prepareContext(tomcat.getHost(),initializers);
//准备启动
returngetTomcatWebServer(tomcat);
}
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){
stopSilently();
thrownewWebServerException("UnabletostartembeddedTomcat",ex);
}
}
}
备注:在这个过程中我们需要了解Bean的生命周期,Tomcat的三个定制器均在BeanPostProcessorsRegistrar(Bean后置处理器)过程中加载;
构造方法-->Bean后置处理器Before-->InitializingBean-->init-method-->Bean后置处理器After
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
protectedObjectdoCreateBean(finalStringbeanName,finalRootBeanDefinitionmbd,final@NullableObject[]args)
throwsBeanCreationException{
//Instantiatethebean.
BeanWrapperinstanceWrapper=null;
if(mbd.isSingleton()){
instanceWrapper=this.factoryBeanInstanceCache.remove(beanName);
}
if(instanceWrapper==null){
//构造方法
instanceWrapper=createBeanInstance(beanName,mbd,args);
}
finalObjectbean=instanceWrapper.getWrappedInstance();
Class>beanType=instanceWrapper.getWrappedClass();
if(beanType!=NullBean.class){
mbd.resolvedTargetType=beanType;
}
//Initializethebeaninstance.
......
returnexposedObject;
}
protectedObjectinitializeBean(finalStringbeanName,finalObjectbean,@NullableRootBeanDefinitionmbd){
if(System.getSecurityManager()!=null){
AccessController.doPrivileged((PrivilegedAction
总结
到此这篇关于springboot基于Tomcat容器的自启动流程分析的文章就介绍到这了,更多相关springboottomcat自启动内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。