一、前言
- Springboot源码解析是一件大工程,逐行逐句的去钻研代码,会很干燥,也不容易坚持下去。
- 咱们不谋求大而全,而是试着每次去钻研一个小知识点,最终聚沙成塔,这就是咱们的springboot源码管中窥豹系列。
二、web服务器
- 以前的的spring我的项目或者springmvc我的项目都须要一个web服务器,tomcat,或者其它的
- 应用springboot之后,咱们不再须要配置web服务器,因为springboot帮咱们集成了
- 明天咱们来剖析一下源码,看看在哪里实现的,知其然知其所以然
三、源码剖析
- 还是从SpringApplication的run办法开始看
- 不相熟的能够看之前的文章:springboot源码解析-管中窥豹系列之总体构造(一)
SpringApplication.javapublic ConfigurableApplicationContext run(String... args) { ... try { ... refreshContext(context); ... } catch (Throwable ex) { ... } ... return context;}
- 接着进入到 refreshContext(context) 外面
AbstractApplicationContext.java@Overridepublic void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... try { ... // Initialize other special beans in specific context subclasses. onRefresh(); ... } catch (BeansException ex) { ... } finally { ... } }}
- 进入到 onRefresh() 办法
protected void onRefresh() throws BeansException { // For subclasses: do nothing by default.}
- 留神这个是一个protected办法,咱们进入到子实现外面
- 具体用的哪个context,请看之前的文章:springboot源码解析-管中窥豹系列之我的项目类型(二)
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context." + "annotation.AnnotationConfigApplicationContext";public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot." + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework." + "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { switch (this.webApplicationType) { case SERVLET: contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS); break; case REACTIVE: contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default: contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);}
- 最罕用的就是一般web我的项目,咱们看这一个
- 咱们到org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext外面找 onRefresh() 办法
- 没找到,在父类ServletWebServerApplicationContext外面找到了
ServletWebServerApplicationContext.java@Overrideprotected void onRefresh() { super.onRefresh(); try { createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server", ex); }}
- 咱们到 createWebServer() 办法外面
private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = getServletContext(); if (webServer == null && servletContext == null) { ServletWebServerFactory factory = getWebServerFactory(); this.webServer = factory.getWebServer(getSelfInitializer()); } else if (servletContext != null) { try { getSelfInitializer().onStartup(servletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } } initPropertySources();}
- 用的工厂模式,先找到工厂getWebServerFactory()
- 再用工厂生成webServer, factory.getWebServer(getSelfInitializer())
- 先看看 getWebServerFactory() 这个办法
protected ServletWebServerFactory getWebServerFactory() { // Use bean names so that we don't consider the hierarchy String[] beanNames = getBeanFactory() .getBeanNamesForType(ServletWebServerFactory.class); if (beanNames.length == 0) { throw new ApplicationContextException( "Unable to start ServletWebServerApplicationContext due to missing " + "ServletWebServerFactory bean."); } if (beanNames.length > 1) { throw new ApplicationContextException( "Unable to start ServletWebServerApplicationContext due to multiple " + "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames)); } return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);}
- 获取惟一的工厂:ServletWebServerFactory,多了少了都不行
- 在哪加载进springboot的呢?
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <scope>compile</scope></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <scope>compile</scope></dependency>
- spring-boot-starter-web外面是蕴含了spring-boot-starter依赖的
- spring-boot-starter外面蕴含了spring-boot-autoconfigure依赖
- spring-boot-autoconfigure外面有一个类:ServletWebServerFactoryConfiguration
- 这个类外面有一个动态类: EmbeddedTomcat
@Configuration(proxyBeanMethods = false)@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)static class EmbeddedTomcat { @Bean TomcatServletWebServerFactory tomcatServletWebServerFactory( ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers, ObjectProvider<TomcatContextCustomizer> contextCustomizers, ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); factory.getTomcatConnectorCustomizers() .addAll(connectorCustomizers.orderedStream().collect(Collectors.toList())); factory.getTomcatContextCustomizers() .addAll(contextCustomizers.orderedStream().collect(Collectors.toList())); factory.getTomcatProtocolHandlerCustomizers() .addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList())); return factory; }}
- ConditionOnClass : 它依赖 Servlet.class, Tomcat.class, UpgradeProtocol.class
- ConditionalOnMissingBean: 避免反复加载
- 至此,factory怎么加载进spring就找到了
- 咱们多看一点,这个类ServletWebServerFactoryConfiguration还有两个动态类
@Configuration(proxyBeanMethods = false)@ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)static class EmbeddedJetty { @Bean JettyServletWebServerFactory JettyServletWebServerFactory( ObjectProvider<JettyServerCustomizer> serverCustomizers) { JettyServletWebServerFactory factory = new JettyServletWebServerFactory(); factory.getServerCustomizers().addAll(serverCustomizers.orderedStream().collect(Collectors.toList())); return factory; }}@Configuration(proxyBeanMethods = false)@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)static class EmbeddedUndertow { @Bean UndertowServletWebServerFactory undertowServletWebServerFactory( ObjectProvider<UndertowDeploymentInfoCustomizer> deploymentInfoCustomizers, ObjectProvider<UndertowBuilderCustomizer> builderCustomizers) { UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory(); factory.getDeploymentInfoCustomizers() .addAll(deploymentInfoCustomizers.orderedStream().collect(Collectors.toList())); factory.getBuilderCustomizers().addAll(builderCustomizers.orderedStream().collect(Collectors.toList())); return factory; }}
- 一个是生成jetty服务器工厂,一个是生成undertow服务器工厂
- 它们的加载,取决于依赖的class是否存在
- tomcat: Servlet.class, Tomcat.class, UpgradeProtocol.class
- jetty: Servlet.class, Server.class, Loader.class, WebAppContext.class
- undertow: Servlet.class, Undertow.class, SslClientAuthMode.class
如果咱们想换成undertow服务器,依赖改了就行了
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId></dependency>
如果咱们想换成jetty服务器,同理
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId></dependency>
- 思维拉回来,工厂有了,咱们看看工厂怎么生成的webServer
TomcatServletWebServerFactory.java@Overridepublic WebServer getWebServer(ServletContextInitializer... initializers) { if (this.disableMBeanRegistry) { Registry.disableRegistry(); } Tomcat tomcat = new Tomcat(); File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat"); tomcat.setBaseDir(baseDir.getAbsolutePath()); Connector connector = new Connector(this.protocol); connector.setThrowOnFailure(true); tomcat.getService().addConnector(connector); customizeConnector(connector); tomcat.setConnector(connector); tomcat.getHost().setAutoDeploy(false); configureEngine(tomcat.getEngine()); for (Connector additionalConnector : this.additionalTomcatConnectors) { tomcat.getService().addConnector(additionalConnector); } prepareContext(tomcat.getHost(), initializers); return getTomcatWebServer(tomcat);}
- 这个办法咱们就不剖析了,就是生成tomcat服务器,和spring关联不大,改天咱们专门剖析tomcat源码
- 至此,整个springboot的加载web服务器过程就完了
欢送关注微信公众号:丰极,更多技术学习分享。