山亭建设局网站,58同城做网站被骗,深圳对留学生创业政策,平面设计网课培训有用吗背景 1 大家都知道SpringBoot是通过main函数启动的#xff0c;这里面跟踪代码到处都没有找到while(true)#xff0c;为什么启动后可以一直跑#xff1f; 2 SpringBoot默认使用tomcat作为web容器。大家也可以通过在pom文件中exclusion掉tomcat#xff0c;denpendenc…背景 1 大家都知道SpringBoot是通过main函数启动的这里面跟踪代码到处都没有找到while(true)为什么启动后可以一直跑 2 SpringBoot默认使用tomcat作为web容器。大家也可以通过在pom文件中exclusion掉tomcatdenpendency jetty 的方法来使用jetty。那SpringBoot是怎么做到在不同web容器之间切换的呢 2 传统的web容器比如jetty本质上是直接通过java start.jar 来启动之后来加载spring上下文的SpringBoot通过main函数是怎么来启动web容器的呢 本文就这三个问题展开论述。 问题1分析 问题1很简单启动后一直跑是因为启动了线程池。原理就是有非deamon的线程在跑。Java虚拟机规范定义要等所有用户线程都运行完才会退出。 所以这个原理就和下面启动线程池一样 程序员修炼之道教我们不要假定要证明。虽然jetty使用线程池是常识我们也来跟踪下源码看看线程池是在哪里初始化的 org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory类里创建Server的使用使用线程池作为初始化参数。然后创建了socket连接来监听端口。对于socket连接有之前没接触过的可以自己查一下。建议动手实践。《Java异常处理总结》这篇文章里有不错的简单小例子可以实操下。 到这里大家应该都明白了为什么启动后一直不停。但是又有疑问了JettyServletWebServerFactory是个什么东东 问题2分析 关于问题2我们写个最简单的类来debug一下 进入SpringAppication.run的源码可以看到里面创建了一个context默认是AnnotationConfigServletWebServerApplicationContext。一初始化在Bean定义里就加载了spring开天辟地的5个Bean。 继续向下执行走到AbstractApplicationContext的refresh方法执行到onRefresh时你进入方法里发现实际上执行的是
ServletWebServerApplicationContext的onFresh 这里面实际只做了一件事创建web服务。 进入这个方法debug到getWebServerFactory 来看一下 获取的正式JettyServletWebServerFactory。为啥不是TomcatServlet呢ServletWebServerFactoryAutoConfiguration的源码很好的说明了这个问题。源码的大意是当tomcat依赖存在就用tomcat不然就按顺序找jetty存不存在不存在再找Undertow存不存在。找到了就返回这个bean作为Servlet的工厂类。 Configuration
AutoConfigureOrder(-2147483648)
ConditionalOnClass({ServletRequest.class})
ConditionalOnWebApplication(type Type.SERVLET
)
EnableConfigurationProperties({ServerProperties.class})
Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class})
public class ServletWebServerFactoryAutoConfiguration {public ServletWebServerFactoryAutoConfiguration() {}Beanpublic ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {return new ServletWebServerFactoryCustomizer(serverProperties);}BeanConditionalOnClass(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;public BeanPostProcessorsRegistrar() {}public void setBeanFactory(BeanFactory beanFactory) throws BeansException {if (beanFactory instanceof ConfigurableListableBeanFactory) {this.beanFactory (ConfigurableListableBeanFactory)beanFactory;}}public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {if (this.beanFactory ! null) {this.registerSyntheticBeanIfMissing(registry, webServerFactoryCustomizerBeanPostProcessor, WebServerFactoryCustomizerBeanPostProcessor.class);this.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);}}}
}至此第二个问题也真相大白。 问题3分析 第三个问题是传统的web容器比如jetty本质上是直接通过java start.jar 来启动之后来加载spring上下文的SpringBoot通过main函数是怎么来启动web容器。 这个问题在前面问题分析过程中也给了很多线索。我们来回顾下SpringApplication.run里会创建Spring的应用上下文默认是AnnotationConfigServletWebServerApplicationContext。首先会加载Spring开天辟地的5个Bean。然后它初始化各种Bean工厂。 SpringBoot在ServletWebServerApplicationContext中重载了onRefresh方法除了以前Spring默认的onRefresh方法外还增加了createWebServer方法在这个方法中对Web容器进行了初始化工作。 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactIdversion${spring.boot.version}/versionexclusionsexclusiongroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-logging/artifactId/exclusionexclusiongroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-tomcat/artifactId/exclusionexclusiongroupIdcom.fasterxml.jackson.core/groupIdartifactIdjackson-databind/artifactId/exclusion/exclusions
/dependency
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-jetty/artifactIdversion${spring.boot.version}/versionexclusionsexclusiongroupIdorg.eclipse.jetty.aggregate/groupIdartifactIdjetty-all/artifactId/exclusion/exclusions
/dependency 因为选择servlet容器是类似于使用基于条件的注解方式。因为当exclusion掉tomcat后只有jetty满足条件所以会加载JettyServletWebServerFactory。 通过getWebServer方法会new一个WebServer对象new对象的方法会调用initialize方法在这个方法中会对容器进行初始化并启动。 而容器启动的基本原理就是创建个线程池和网络套接字。用线程去处理套接字读写的内容。 总结 文本用带有少许说明的三个问题开场展开论述实际是使用了麦肯锡大法中的SCQA架构。 SCQA架构是金字塔模型里面突出的一个论述方法即“情境Situation、冲突Complication、问题Question、答案Answer”。可以帮助我们在陈述事实时条理更为清晰、有效。 SCQA其实只是麦肯锡做了总结。这个方法李清照都在用
昨夜雨疏风骤浓睡不消残酒 情境
试问卷帘人渠道海棠依旧冲突
知否知否问题
应是绿肥红瘦答案 文章正文看似一步步回答问题实际上在讲述怎样去看spring源码了解spring原理的一个过程。即带着问题去看debug跟踪源码验证 的方法。