寄人篱下的日子
一直以来受传统影响, 我们的 web 工程总是打成 war 包, 然后放入 tomcat 的 webapps 目录下面.
如下图 01:
当 tomcat 启动时, 会去解压 war 包, 然后运行 Web 工程. 这大家都非常熟悉了.
用一个抽象的图形表示, 就是这样子. 如下图 02:
在一个大大的 tomcat 里面, 有一个小小的 war 包, 貌似没有地位啊.
不知道有没有人思考过这两个问题:
1)Spring 在哪里?
2)tomcat 和 war 包是如何联系上的呢?
对于第一个问题, 因为我们的 Web 工程是使用 spring-Web 开发的, 所以 Spring 在 war 包里呢.
Spring 蜷缩在小小的 war 包里, 生活在 tomcat 的屋檐下, 完全一副威风不起来样子.
这简直是叔可忍, 婶也不能忍啊.
对于第二个问题, tomcat 和 war 包在代码上没啥关系. 它们其实是通过 Java Web 的规范联系上的.
这个规范是这样的, 在某一个 jar 包的 META-INF 目录下, 必须要有一个 services 目录.
在这个目录下必须有一个以 javax.servlet.ServletContainerInitializer 为名字的文件.
显然这个文件名称是一个接口, 所以文件内容就是这个接口的实现类.
拿 Spring 来说, 这个任务自然就落在了 spring-Web-xxx.jar 这个 jar 包里啦.
如下图 03:
因此, tomcat 会扫描 Web 工程里的所有 jar 包, 找到这个文件并读出里面的接口实现类, 然后去调用这个实现类.
这样一来, 启动流程从 tomcat 沿着这个实现类就来到了 Web 工程里面了, Web 工程自然就被启动起来了.
对于 Spring 来说, 这个实现类一定是由 spring-Web 来提供了, 如下图 04:
可以看到 Spring 唯一能访问的就是 ServletContext, 因此 Spring 的整个容器就是在 ServletContext 里面放着呢.
这就是传统的 spring-Web 工程与 tomcat 的关系.
Spring 就一活脱脱的小弟, 被埋在 tomcat 里面, 它不甘心啊.
Spring 一心想成为大老虎, 无奈只能被当作 Hello Kitty, 宝宝心里苦啊.
翻过身来成主人
Spring 一直努力着, 等待着, 寻找着, 观察着, 终于机会来了.
它就是 SpringBoot, 是它让 Spring 翻身成了主人, 是它让 Spring 百尺竿头更进一步, 掌声响起来.
现在可以用下面这个图形表示, 如下图 05:
成功实现了 "权力反转",SpringBoot 成了老大, 把 tomcat 纳入了麾下.
有时候不得不感慨, 真是一念之间, 地狱天堂啊.
除此之外, 其实 SpringBoot 更进了一步, 它干脆一统了 Web 服务器.
也就是说, 它那天看 tomcat 不爽了, 分分钟换成 jetty 或 netty.
原来它只有一席之地, 现在却拥有了星辰大海. 不要太爽了.
当然, 为此呢, 它需要付出一些额外劳动, 不过这个买卖依然非常划算.
因为以有限的代价, 换来了无限的可能. 现在它就是启动入口, 它想怎么折腾都行.
不得不说, 当大哥的感觉真好, 如果再有个大嫂, 那就更好了, 哈哈.
SpringBoot 统一 Web 可能还有一个原因, 就是要支持响应式 Web, 这样整体看起来更加对称.
抽象几个接口, 认真封装一下
实现统一 Web 服务器方案其实就是, 抽象几个接口, 认真封装一下. 真是这样的.
首先, 得有个 Web 服务器接口吧, 如下图 06:
一般的人看到这个接口, 心中想的是这个接口好简单啊.
二般的人看到这个接口, 心中想的是这个接口抽象程度很高啊, 说明它的不同实现之间差异化一定很大.
因为抽象程度低的话, 不足以抽象出共性, 不足以抹平差异化.
所以接口就是它的不同实现类之间的交集, 差异化越大的, 它们之间的交集就越小.
看下这个接口的不同实现类, 如下图 07:
其实就是基于已有的不同 Web 服务器的封装. 不同的 Web 服务器, 是不同的团队设计开发的, 几乎没有什么共性.
但总归都要启动和停止, 都要有个端口吧. 所以这个接口就是它现在这样子.
差异化很大的东西, 它们的创建过程也一定有较大的差异化, 此时一般使用工厂去创建, 如下图 0809:
一个是创建基于 Servlet 的 Web 服务器, 一个是创建基于响应式的 Web 服务器.
这样就实现不同的工厂, 来创建不同的 Web 服务器即可. 如下图 1011:
我们可以看到 netty 这个 Web 服务器是不支持 Servlet 的, 只支持 Reactive.
这就是整个的抽象思路和实现过程, 原理很简单, 但是实现起来要足够的专业.
就像造车一样, 造好了就是汽车, 造不好就是拖拉机, 虽然都能开, 但是一个天上一个地下.
音乐渐起, 华灯初上
从一开始 spring-Web 和 tomcat 靠一个 Java Web 的规范连在一起. 处于非常被动的地位.
到 SpringBoot 出现带来的成功翻身, 把自己变成了启动入口, 变成了主体.
不仅可以操作 Web 服务器 API, 而且还统一了它们. 从被动变成了主动地位.
SpringBoot 把握住了入口, 这就为它开辟了更为广阔的天地, 可以放心去追求诗和远方了.
音乐渐起, 华灯初上, 一切美好才刚刚开始...
>>> 玩转 SpringBoot 系列文章 <<<[玩转 SpringBoot] 配置文件 YAML 的正确打开姿势
[玩转 SpringBoot] 用好条件相关注解, 开启自动配置之门
[玩转 SpringBoot] 给自动配置来个整体大揭秘
[玩转 SpringBoot] 看似复杂的 Environment 其实很简单
>>> 品 Spring 系列文章 <<< 品 Spring: 帝国的基石
品 Spring:bean 定义上梁山
品 Spring: 实现 bean 定义时采用的 "先进生产力"
品 Spring: 注解终于 "成功上位"
品 Spring: 能工巧匠们对注解的 "加持"
品 Spring:SpringBoot 和 Spring 到底有没有本质的不同?
品 Spring: 负责 bean 定义注册的两个 "排头兵"
品 Spring:SpringBoot 轻松取胜 bean 定义注册的 "第一阶段"
品 Spring:SpringBoot 发起 bean 定义注册的 "二次攻坚战"
品 Spring: 注解之王 @Configuration 和它的一众 "小弟们"
品 Spring:bean 工厂后处理器的调用规则
品 Spring: 详细解说 bean 后处理器
品 Spring: 对 @PostConstruct 和 @PreDestroy 注解的处理方法
品 Spring: 对 @Resource 注解的处理方法
品 Spring: 对 @Autowired 和 @Value 注解的处理方法
品 Spring: 真没想到, 三十步才能完成一个 bean 实例的创建
品 Spring: 关于 @Scheduled 定时任务的思考与探索, 结果尴尬了
>>> 热门文章集锦 <<<
毕业 10 年, 我有话说
[面试] 我是如何面试别人 List 相关知识的, 深度有点长文
我是如何在毕业不久只用 1 年就升为开发组长的
爸爸又给 Spring MVC 生了个弟弟叫 Spring WebFlux
[面试] 我是如何在面试别人 Spring 事务时 "套路" 对方的
[面试] Spring 事务面试考点吐血整理 (建议珍藏)
[面试] 我是如何在面试别人 Redis 相关知识时 "软怼" 他的
[面试] 吃透了这些 Redis 知识点, 面试官一定觉得你很 NB(干货 | 建议珍藏)
[面试] 如果你这样回答 "什么是线程安全", 面试官都会对你刮目相看 (建议珍藏)
[面试] 迄今为止把同步 / 异步 / 阻塞 / 非阻塞 / BIO/NIO/AIO 讲的这么清楚的好文章 (快快珍藏)
[面试] 一篇文章帮你彻底搞清楚 "I/O 多路复用" 和 "异步 I/O" 的前世今生 (深度好文, 建议珍藏)
[面试] 如果把线程当作一个人来对待, 所有问题都瞬间明白了
Java 多线程通关 --- 基础知识挑战
品 Spring: 帝国的基石
作者是工作超过 10 年的码农, 现在任架构师. 喜欢研究技术, 崇尚简单快乐. 追求以通俗易懂的语言解说技术, 希望所有的读者都能看懂并记住. 下面是公众号的二维码, 欢迎关注!
来源: https://www.cnblogs.com/lixinjie/p/playing-springboot-005.html