![深入理解Spring Cloud与实战](https://wfqqreader-1252317822.image.myqcloud.com/cover/869/41202869/b_41202869.jpg)
1.2 Spring Boot核心特性
1.2.1 Web服务器:WebServer
内置Servlet容器已经成为过去式了,新版本的Spring Boot将此特性称为WebServer。
早期的Java Web应用都需要构造成WAR包(WEB-INF目录下有个 web.xml文件,大家一定不陌生),然后部署到Servlet容器(比如Tomcat、Undertow、Jetty)。
如果是Spring MVC应用,需要在web.xml中配置DispatcherServlet这个Servlet和对应的url-pattern,url-pattern 默认会拦截所有的请求。DispatcherServlet 拦截请求后,再通过内部的HandlerMapping 根据 URL 信息去匹配 Controller,最终找到匹配到的 Controller,然后使用Controller内部的方法对请求进行处理。
WebServer表示一个可配置的Web服务器(比如TomcatWebServer、JettyWebServer、NettyWebServer、UndertowServletWebServer、UndertowWebServer),可以通过 WebServer 接口对外提供的start方法启动服务器,用stop方法停止服务器。有了WebServer后,我们不再需要关心外部的 Web服务器、web.xml文件、各种 Servlet和 Filter的配置等因素,只需要编写代码并把项目打包成JAR文件后直接运行即可,这非常适合云原生架构中的可独立部署特性。
WebServer接口的定义如下:
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_23_1.jpg?sign=1739608569-LpQSe5hWRQVVuik23HAoe0b1yf0eCrMX-0-935dbd98a6e491a38f52b4972f46db2f)
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_24_1.jpg?sign=1739608569-da6Kp2rqO0mt6B7KtmpoTA71o17v2HMi-0-f7faefd93bf6f28855fd4bcb8a97da85)
对于WebServer,可通过ReactiveWebServerFactory或ServletWebServerFactory工厂接口去创建。这两个工厂接口对应的代码如下:
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_24_2.jpg?sign=1739608569-YdqXHQS4vKW9Aqf3Y0bREdPtvqz3Vt5U-0-d6fd283ffdab68a88b7c6c976058a8ef)
ConfigurableWebServerFactory 接口继承自 WebServerFactory 接口(这是一个空接口)和 ErrorPageRegistry接口(错误页注册表,内部维护错误页信息,提供 addErrorPages方法以添加错误页到 WebServer 中),ConfigurableWebServerFactory 接口表示这是一个可配置的WebServerFactory接口,定义如下:
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_25_1.jpg?sign=1739608569-yxjH6DTfK8dPLDWPT6aRw8HJ8hsWcB79-0-6157dc67c0841844975a65878e3418b8)
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_26_1.jpg?sign=1739608569-S89CC1Aqa4YdTE5VGySGx7EokYQ098AS-0-7caeb328b1e0f9c289e2ee1f6a0adab4)
ConfigurableWebServerFactory 提供了 WebServer 常用的配置信息,它的子接口表示各个WebServer 实现类独有的配置,比如 ConfigurableJettyWebServerFactory对应 Jetty独有的配置,ConfigurableTomcatWebServerFactory对应 Tomcat 独有的配置。真正创建 WebServer的工厂类(如 TomcatServletWebServerFactory)通过继承和实现接口的方式实现了 ConfigurableWebServer-Factory和ServletWebServerFactory这两个接口。
Spring Boot对于 WebServer概念新增了一些事件,比如 WebServerInitializedEvent 事件,表示ApplicationContext刷新过后且WebServer处于ready状态下会触发的事件。
提示:Spring Cloud服务注册的时机就是在WebServerInitializedEvent事件被触发的时候。
我们常用的 spring-boot-starter-web 模块默认使用的是 Tomcat(Pom 里存在 spring-boot-starter-tomcat依赖),如果要使用Undertow或者Jetty,需要在 spring-boot-starter-web 依赖中排除 spring-boot-starter-tomcat 依赖,然后加上 spring-boot-starter-undertow (对应Undertow)或spring-boot-starter-jetty(对应Jetty)依赖。
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_26_2.jpg?sign=1739608569-BZpnUyvxZC3DnG3w318zMzvTY1YFF6y6-0-829fa708d39409f9e11c27b2a918ea52)
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_27_1.jpg?sign=1739608569-MAqLa07pCun2oXihk0CkhEnu6Fweoe9x-0-0af28a93a1c8cb991524bed5d44e203e)
若要使用NettyServer,则需要使用 spring-boot-starter-webflux(内部的 spring-boot-starter-reactor-netty 触发 ReactiveWebServerFactoryConfiguration#EmbeddedNetty 自动化配置生效)代替spring-boot-starter-web。
1.2.2 条件注解:@ConditionalOnXX
Spring Boot 有一个很重要的模块—spring-boot-autoconfigure,该模块内部包含了很多第三方依赖的 AutoConfiguration(自动化配置类),比如 KafkaAutoConfiguration、GsonAutoConfiguration、ThymeleafAutoConfiguration、WebMvcAutoConfiguration 等。这些AutoConfiguration只会在特定的情况下才会生效,这里的特定情况其实就是条件注解。
Spring Boot提供的条件注解如表1-1所示。
表1-1
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_27_2.jpg?sign=1739608569-CHQuH0qVtGgWV9Ww41PVCHJISKwVa1Nc-0-da8c0d362b6400464e12e7ce4dc5b956)
续表
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_28_1.jpg?sign=1739608569-NlzDxMWPqASJNKTGkEIEocs7GGm1hXgy-0-88e7ded1429c80211b85a86e2a7a9a47)
表 1-1中,条件注解仅仅只是一个注解,真正的判断逻辑在这些条件注解的解析类内部。解析类内部会根据注解的属性来判断是否满足条件,比如,OnJavaCondition条件注解解析类对应的是@ConditionOnJava条件注解,其内部会判断当前应用的JDK版本是否正确。内部处理逻辑的代码如下:
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_28_2.jpg?sign=1739608569-URuLYm8RFGWWqHxIOaYd9iudQWuLbk7Q-0-71dba08dbfe7ac330a15df14e8842f0b)
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_29_1.jpg?sign=1739608569-PkeFtBOKAKDHX2TmB0ZLyCxB0iH5r7PX-0-b26cf2e0ec3668c0f41fe52898536180)
理解了这些条件注解后,Spring Boot在哪里使用这些条件注解来判断是否需要加载自动化配置类呢?Spring Boot通过spring-context模块中提供的ConditionEvaluator完成这个动作。
ConditionEvaluator在 AnnotatedBeanDefinitionReader、ClassPathScanningCandidate-ComponentProvider、ConfigurationClassBeanDefinitionReader、ConfigurationClassParser、AnnotatedBeanDefinitionReader 这些类扫描组件、配置类解析组件扫描、解析组件的时候来判断是否需要跳过(skip)某些配置类,具体的解析逻辑这里不再展开介绍。
Spring Cloud内部定义的一些新的条件注解如表1-2所示。
表1-2
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_29_2.jpg?sign=1739608569-mXKJ6jqvPmRVIhXuS8tF0vFKRnhNqt0o-0-b746e0225795507e55d9d1a22b20f83c)
续表
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_30_1.jpg?sign=1739608569-e5RmKK99S1YtDZbRAhQQpSilclSHispL-0-b65d1ee4370e14a523f6f49d8f1ff039)
1.2.3 工厂加载机制
1.2.2 节介绍了条件注解作用于自动化配置类。那么这些自动化配置类是从哪里被加载的呢?这是通过工厂加载机制(factory loading mechanism)来实现的,这个机制会从 META-INF/spring.factories 文件中加载自动化配置类。下面是 spring-boot-autoconfigure 模块里META-INF/spring.factories文件的一部分内容:
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_30_2.jpg?sign=1739608569-KI0aqmvFdRlh9ovNYyT1O4vQDSE8qg6N-0-1b5e8ef4fc58918547b7190f3d5315b5)
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_31_1.jpg?sign=1739608569-o0CXELUM3cIVuWv2K4zON2R6JUB1jyGZ-0-ef2cfaf008e1823a48a29ff7ccec6d84)
spring.factories 是一个 properties 格式的文件。key 是一个类的全称,比如,“org.spring-framework.boot.autoconfigure.EnableAutoConfiguration”,value 是用“,”分割的自动化配置类的全称列表。
启动 Spring Boot 应用的@SpringBootApplication 注解内部被@EnableAutoConfiguration 注解修饰,@EnableAutoConfiguration注解会导入AutoConfigurationImportSelector这个ImportSelector。AutoConfigurationImportSelector内部的selectImports要导入的配置类是通过SpringFactoriesLoader获取的。
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_32_1.jpg?sign=1739608569-bzHJiJY3J2DA6clkD8gmHmJMnUDXJo67-0-900e2d2293d6988668d585ca829ee4c3)
在SpringFactoriesLoader的加载过程中,选择的key(对应spring.factories文件中的key)是EnableAutoConfiguration这个类对应的类全名。
Spring Cloud内部也使用了工厂加载机制并扩展了一些 key。比如,org.springframework.cloud.bootstrap.BootstrapConfiguration用于在Bootstrap过程中加载对应的配置类。
1.2.4 配置加载机制
Spring Boot 把配置文件的加载封装成了 PropertySourceLoader 接口,该接口的定义如下:
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_32_2.jpg?sign=1739608569-aYnuUSqru9e0i4QdRUATEoEinacrPV9t-0-1e1d6bc904b0c574749e5127d784a510)
Spring Boot对于该接口只有两种实现:
·PropertiesPropertySourceLoader:加载properties或xml文件。
·YamlPropertySourceLoader:加载yaml或yml文件。
提示:resources/application.properties 或 resources/application.yaml 配置文件就是被这两种ProperySourceLoader所加载的。
SpringApplication内部维护着一个 ApplicationListener集合属性,用于监听 ApplicationEvent。默认情况下,该属性会被工厂加载机制所加载(加载的 key 为 org.springframework.context.ApplicationListener):
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_33_1.jpg?sign=1739608569-6C0MJgLsfmXBmVsi7HxmLeQAVhrsVtdj-0-406c7272b1ca57b284acd9f0e0a62f6b)
spring-boot模块里的META-INF/spring.factories中存在ConfigFileApplicationListener:
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_33_2.jpg?sign=1739608569-QVXeeRTucb58HXGymBjVxRYXaFxxWQYr-0-8fa70f52d9d1c7ba0bd31d08af1e0b84)
ConfigFileApplicationListener 是 Spring Boot 配置加载的核心类,它实现了 Environment-PostProcessor 接口。EnvironmentPostProcessor 接口是配置环境信息 Environment 的PostProcessor,可以对应用的Environment进行修改。
由于 ConfigFileApplicationListener 实现了 ApplicationListener 接口,会监听 Spring 的事件。其中,对ApplicationEnvironmentPreparedEvent 进行了监听,会调用 onApplicationEnvironment-PreparedEvent方法:
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_33_3.jpg?sign=1739608569-Aqbvsqeo9gtaabEe2JzLyvS9ihRNxkmU-0-2b18662178ae8f1282e4112bf8f15670)
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_34_1.jpg?sign=1739608569-Fw9n4WsCSplwRDxA4xzQGOdXxAWaMvNQ-0-7f138a19cf2b45cdc97b9e443ee6dc04)
ConfigFileApplicationListener 的 postProcessEnvironment方法内部构造了 Loader,并调用load方法进行配置文件的加载:
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_34_2.jpg?sign=1739608569-KP9yHdviKuvTUawXg0Acude2Izj4ovtz-0-9e6bd93eb3c8d24637557da4104b377c)
Loader内部有不少细节,比如,配置文件的文件名是根据spring.config.name配置项来决定的,不设置时默认为 application。默认配置文件的加载路径为 classpath:/、classpath:/config/、file:./和 file:./config/,这个加载路径可以通过 spring.config.location 配置项来修改。spring.profiles.active用于指定生效的profile等,这里不再具体展开介绍。
提示:Spring Cloud在加载过程中把spring.config.name 配置设置成了bootstrap,所以加载的文件名是bootstrap.properties或bootstrap.yml。
1.2.5 Spring Boot Actuator
Spring Boot 提供了不少 Production-ready 的特性,这些特性需要引入模块 spring-boot-starter-actuator才能自动生效。
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_35_1.jpg?sign=1739608569-WauWjuX5vgVugyDT6EStG4sXPAlvMGaJ-0-216d9782d768dab92d0d491d028d4421)
其中,Endpoint 是比较核心的功能,其作用是让我们监控应用,以及跟应用之间的交互。比如,Health Endpoint、HttpTrace Endpoint 用于应用的健康检查和 HTTP 历史链路(应用监控),Loggers Endpoint用于动态改变应用的日志级别(应用交互)。
表1-3列出了常用的一些Endpoint。
表1-3
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_35_2.jpg?sign=1739608569-xkTFKjIOa5BiyIu0sUOYaU98NRqVsgrv-0-e32f19300fffb07c0f22eb00930c0e46)
续表
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_36_1.jpg?sign=1739608569-m2IVshh7CBkryZ8aYxkWV29ukXQpPTPe-0-1d77d330a9e91adf40fefdb593ff7425)
提示:在Spring Boot 2.x以后的版本中,Endpoint 对应的路径是/actuator/endpointid;对于Spring Boot 1.x,路径是/endpointid。
Spring Cloud也创建了一些新的Endpoint,如表1-4所示。
表1-4
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_36_2.jpg?sign=1739608569-iQ38ZTWKoHQlmfCoXmHKRqMD22yu5kE6-0-92931539bbe0e1ec3f0dc7b306173acf)
Spring Cloud母公司Pivotal旗下的Cloud Foundry产品基于Endpoint做了很多图形化的界面,例如,Health Endpoint(健康检查)对应的界面如图1-1所示,Loggers Endpoint(修改日志级别)对应的界面如图1-2所示,HttpTrace Endpoint(显示HTTP链路)对应的界面如图1-3所示。
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_36_3.jpg?sign=1739608569-Jk2Di8MScjM2wJ4H0eVvFyTNlt6flJFf-0-0c0ec5331e0a3da714889ef857a6f76a)
图1-1
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_37_1.jpg?sign=1739608569-FRdxwa701unqQxtV4Fl3cybkCCK7gUvV-0-1f0f1ae001631e3460cc75409a1132c1)
图1-2
![](https://epubservercos.yuewen.com/8E18D1/21440186401518706/epubprivate/OEBPS/Images/39973_37_2.jpg?sign=1739608569-OnHhnSEPyS2jOiavXjmqWkmR9Ucm4oOl-0-2dfa307296499919888489dadc5fc42a)
图1-3
对Spring Boot的核心概念有了一定的了解之后,我们开始进入Spring Cloud世界。