Spring 核心技术与产品理念剖析【上】

IT 技术发展太快了,就像浪潮一样一波接着一波,朝你迎面扑来,稍不留神就会被巨浪卷至海底而不得翻身。我们必须要学会抓住那些不变的本质或规律,只有这样才能屹立潮头而不倒,乘风破浪,做这个巨变时代的弄潮儿!

2003年,Rod Johnson 创建了 Spring,我在那一年开始了研究生实习。2005年参加工作,通信行业,主力开发语言是 C/C++。在校勤工俭学时捣鼓过 JSP,2005年前后我开始自学 Spring 搭建个人网站,那时 Java 领域最火的开发框架组合就是:Struts + Spring + Hibernate,SSH。2009年,我跳槽到了移动互联网行业,主力开发语言逐渐转为 Java。2014年,我再次跳槽进了互联网金融行业,基于 Spring 扩展定制内部开发框架,从 Spring 用户变成了扩展开发者。2016年因参与内部云平台建设,我跟 Spring 的东家 Pivotal 公司还有过一次合作。随着微服务等技术的兴起,近些年我做了许多 Spring Boot\Spring Cloud 扩展定制和培训推广。

一晃眼十五年过去了,从取代 EJB 的轻量级开发框架开始,到无比强大的生态圈,再到 Spring Boot\Spring Cloud 重新塑身成为云原生应用开发领域的首选框架。Spring 早已不是最初的模样了,在它身上发生过无数变化,但唯一不变的是它仍旧稳坐 Java 开发框架领域的头把交椅。或许大部分读者都熟悉 Spring 的使用,但你知道它背后的核心技术有哪些吗?这些年它都发生过哪些重大的变化?它演进至 Spring Boot/Spring Cloud 的原因是什么?它的成功源于哪些关键的产品设计理念?...... 熟悉 Spring 的使用仅仅是"知其然",唯有"知其所以然",我们才能真正融会贯通用好它。快来吧,千万不要错过!老兵用血汗经验为你剖析那些风云变幻中的不变量:

  • Spring 背后的核心技术
  • Spring 演进发展的历程
  • Spring Cloud 蝶变重生
  • Spring 的产品设计理念
  • Spring 的产品推广策略
  • ...... 

适读人群:开发、测试、架构、产品等

  • 1. Spring 背后的核心技术

Java EE 或 J2EE,都是 Java Platform Enterprise Edition 的简称,它是一套开发分布式企业级应用的规范和标准,由一整套服务(Services)、应用程序接口(APIs)和协议构成,下面是 J2EE 涵盖的13种技术规范: 

  • JDBC:Java Database Connectivity 
  • JNDI:Java Naming and Directory Interface
  • EJB:Enterprise Java Bean
  • RMI:Remote Method Invocation
  • Java IDL for CORBA 
  • JSP:Java Server Pages
  • Java Servlet
  • XML:Extensible Markup Language
  • JMS:Java Message Service
  • JTA:Java Transaction API
  • JTS:Java Transaction Service
  • Java Mail
  • JAF:JavaBeans Activation Framework 

生产力决定生产关系,而科学技术是第一生产力。Java 最早是由 Sun Microsystems 公司发明的高级编程语言,EJB 也是由 Sun Microsystems 公司推行的 J2EE 标准规范,而 Spring 却取代 EJB 成了事实标准,以世俗的眼光看,这是一个经典的以弱胜强的故事。当时,EJB 的背后有许多知名的商业公司提供强力支持,而 Spring 仅仅是 Rod Johnson 个人的玩票作品,为什么最终结局出乎意料呢?其实,弱是无法胜强的,只是当时世人看不懂 Spring 比 EJB 强在什么地方,现在我们再去剖析就知道它强在技术上,先进的技术造就了 Spring 的轻量和易用,再加上开源免费的商业模式,最终赢得用户。

那究竟哪些核心技术造就了 Spring 的辉煌呢?除了最著名的控制反转 IOC、依赖注入 DI 和面向切面编程 AOP 等外,还有 MVC、Taglib、ORM、Annotation 等,以及对 J2EE 其他标准规范的支持,包括:JDBC、JNDI、RMI、JMS 等,接下来我们简单介绍一下这些关键技术,如果想更加深入的了解,大家可以找资料做专题学习。 

  • 1.1 IOC / DI / AOP

Spring 作为开源框架,为了降低企业应用的开发复杂度的人创建,但现在它已经不限于企业应用这个领域了,而是一个轻量级的控制反转 IoC(Inversion of Control)和面向切面 AOP(Aspect Oriented Programming)的容器框架。通过 IoC 技术让应用达到松耦合的目的,通过面向切面编程分离业务逻辑与系统服务。IoC 容器负责管理所有应用对象的配置和生命周期,将简单的组件配置、组合成为复杂的应用。

控制反转 IoC 的另外一个说法就是依赖注入 DI(Dependency Injection),它规范了对象与被依赖对象之间的装配过程,对象通过构造器参数、工厂方法参数、属性设置函数来声明依赖关系。IoC 容器提供装配和管理 Bean 功能,整个装配过程由 IoC 容器调度控制的,它在创建对象实例过程中将其所依赖的实例注入,这跟 Bean 直接通过构造器或者 Service Locator 模式自己控制初始化或定位所依赖实例的过程是相反的。

接口 org.springframework.context.ApplicationContext 就代表了 Spring IoC 容器,它负责初始化、配置、装配和管理全部 Bean。IoC 容器通过读取 XML、注解或 Java 类中配置元数据获得初始化、配置和装配相关的指令,我们采用上述配置方式来描述构成应用的对象及彼此之间的依赖关系。IoC/DI 让应用不再强依赖框架,借助配置文件、注解等方式就可以灵活装配出应用程序,前端 Web 框架已经兴替了无数款:Struts、Webwork、JSF、Tapestry、AngularJS、React、Vue 等等,持久层也有不少选择:Hibernate、iBatis、MyBatis 等,但装配领域唯有 Spring 一枝独秀。

从装配这个角度看,Spring 对业务是非侵入性的,业务代码不依赖 Spring,即剥离 Spring 重新换一套框架或者自己写一套组装代码,原先的业务代码是可以重用的。IoC 最初的目的就是充分利用 OO 的多态性,通过配置文件而不是硬编码来实例和装配对象,这样就为具备了为不同客户场景提供服务的灵活性。

AOP 通过静态期预编译或运行期动态代理等方式实现不修改源代码的情况下给程序动态统一添加功能,它给出了独特的编程视角,以切面方式控制系统的各个处理环节,为许多业务场景提供优雅的解决方案,例如:将日志记录、性能统计、安全控制、事务处理、异常处理等代码从业务逻辑代码中划分出来,修改这些行为时不影响业务代码。 

  • 1.2 MVC / MVP / MMVM

  • 视图(View):用户交互界面,数据展示。
  • 控制器(Controller):处理请求的业务逻辑,选择视图展示。
  • 模型(Model):业务逻辑和数据,数据保存访问操作。
  • View 接受用户操作指令,并传送指令至 Controller。
  • Controller 完成业务逻辑处理之后,要求 Model 改变状态。
  • Model 将新数据发送到 View,用户得到更新反馈。

MVP 模式将 MVC 中的 Controller 改为 Presenter,同时改变了通信方向。

  • 每个部件之间的通信都是双向的。
  • View 跟 Model 不直接交互,全部通过 Presenter 传递。
  • View 非常薄,不包含任何业务逻辑,称作"被动视图"(Passive View),即没有任何主动性,而 Presenter 非常厚,所有逻辑都部署在那里。

MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。唯一的区别是,它采用双向绑定(data-binding):View 的变动,自动反映在 ViewModel,反之亦然。React 和 Vue 等都采用这种模式。 

  • 1.3 JDBC / ORM 

Java 数据库连接 JDBC(Java DataBase Connectivity)是用于执行 SQL 语句的 Java API,可以为多种关系数据库提供统一访问:

 对象关系映射 ORM(Object Relational Mapping),是一种用于实现面向对象编程语言里对象跟不同类型关系数据库数据之间的转换技术:

  • 2. Spring 演进发展的历程

2002年,老兵哥我本科毕业,当时正是 J2EE、EJB 最火的时候,许多业内知名的大公司(例如:Sun Microsystems、Oracle、IBM 等)都在推动 EJB 相关技术的发展和落地。当年还是年轻小伙的美国人 Rod Johnson 认为 EJB 太过于臃肿,并不是所有项目都适用 EJB 这种重型框架,他坚信有其他更加优雅的解决方案。为了验证自己的想法,Rod Johnson 在2002年10月出版了一本书《Expert one on one J2EE development without EJB》,在书中他剖析了 J2EE、EJB 框架中存在的一些关键缺陷。Rod Johnson 坚定地认为:

  • J2EE 应该变得更易于使用。
  • 面向接口(Interface)编程要优于面向类(Class),面向接口可以极大地降低复杂度。
  • JavaBean 提供了一种非常好的应用配置途径。
  • 面向对象设计比任何一种实现技术都更加重要,包括 J2EE。
  • 检查型异常在 Java 当中被过度使用,当系统不能从异常中恢复时,平台不应该强迫你去捕获异常。
  • 可测试性是非常重要的,像 Spring 这样的平台应该帮助你把代码变得更易于测试。
  • 使用 Spring 应该是件愉悦的事情。
  • 用户的应用代码不应该依赖任何 Spring 的 APIs。
  • Spring 不应该跟现在已有的优秀解决方案竞争,而是要开放地集成这些第三方组件。

同时,他提出了一套基于普通 Java 类依赖注入的轻量级解决方案,并且以一个在线座位预定系统为例演示了如何在不使用 EJB 的情况下构建高质量、可扩展的系统。为了构建这个演示应用,他编写了超过 30,000 行的基础结构代码,随书籍开源而别广泛引用。由于该开源工程的根包命名为:com.interface21,所以大家最初称这套开源框架为:Interface21,它就是 Spring 的前身,这是一个无心插柳柳成荫的故事。

随着 Interface21 被越来越多的用户认可及使用,Rod Johnson 拥有了跟 EJB 分庭抗礼的勇气和信心,后来他就开始全职投入,并在2004年3月24日对外发布了 Spring Framework 1.0 final。当时,整个 Spring 就是一个完整的项目,所有功能都包含在这个项目当中,其中包含最核心的控制反转 IOC 和面向切面编程 AOP,除此之外还包括:JDBC、Mail、ORM、事务、定时任务、Spring MVC等配套功能。

站在今天回望过去,当年 Rod Johnson 还做对了一件事情,就是拥抱开放、开源,在 Spring 1.x 阶段就已经支持许多第三方开源框架了,例如:Struts、Hibernate、iBatis、模板引擎等。从 Spring 诞生到现在的十五年左右时间,正是软件开源运动蓬勃发展的十五年。Spring 借助开源社区的力量,汇聚全球贡献者,才形成了无比强大的生态圈,才具备了与传统软件业巨头竞争的能力,而 EJB 选择了封闭,差之毫厘谬以千里。

  • 2.1 Spring 1.x

Spring 1.x 主要满足了当时正在兴起的企业应用规模化开发需求,当时 J2EE 应用的经典架构是分层架构:表现层、业务层、持久层,最流行的组合就是 SSH:Struts、Spring、Hibernate。Spring 1.x 仅仅支持基于 XML 的配置,确保用户代码不依赖 Spring。Spring 1.x 主要包含了以下功能模块:aop、beans、context、core、dao、ejb、jdbc、jndi、mail、metadata、orm、remoting、scheduling、transation、ui、util、validation、web 等。

  • 2.2 Spring 2.x

相对于 Spring 1.x,2.x 并没有发生太大的改动,主要是在 1.x 的基础上渐进式的增强,增加了下述新的功能模块:cache.ehcache、instrument、jca、jms、jmx、scripting、stereotype 等。

老兵哥觉得,用户就像手中的沙子,抓的越紧漏的越快,Spring 倡导不绑定用户,业务代码不依赖 Spring,随时可以从 Spring 迁移到其他框架下,Spring 对松耦合的坚持反而让越来越多的用户从 EJB 转投至它的名下。在势头正猛之时,Spring 2.x 顺势推出了对 Java Annotation 的支持。虽然基于注解的配置对用户代码存在一定的入侵,但该特性可以极大地方便用户,配置跟代码在一起,这样更加直观便于维护。

  • 2.3 Spring 3.x

Spring 以简单适配的方式集成第三方开源组件,随着它本身的功能越来越丰富,以及生态圈越来越强大,单个项目工程已经无法满足开发、维护和使用的要求了,Spring 3.x 将原先单个工程项目拆解成多个子项目,这样方便用户按需选用,不像先前的版本,不管用与不用都要引入全部模块。化整为零,这个变化带来了非常大的影响,Spring 不仅是功能模块的堆积了,它开始标准化集成相关的技术了,这有利于构建更加庞大的生态,也更利于获得新的用户。

为什么这么说呢?原先 Spring 是一个整体,用户选不选它是比较大的技术决策,而现在每个组件都是可以单独引入的,相对原先的决策范围变小了,风险也就降低了,用户可以先小范围试用,降低了用户上车的难度。等用户使用上 Spring 的组件,那么跟用户就建立了连接,让用户有更多机会了解 Spring,从而影响用户选用更多的组件。 

Spring 框架被拆解成多个组件,它可以为不同应用架构提供基础的支持,包括消息、事务管理、持久化和前端组件等,它不仅包括 Servlet-based 的 Spring MVC 前端 Web 框架,还包括 Spring WebFlux 等响应式 Web 框架,用户可以按需选择。

在支持 XML、Annotation 配置的基础上,Spring 3.x 还扩展了基于 Java 类的配置。Spring Framework 增加了 Expression、Instructment、Tomcat、oxm 等组件,同时将原来的 Web 细分为:Portlet、Servlet。

  • 2.4 Spring 4.x

沿着 Spring 3.x 组件化的方向,4.x 继续升级演进升级,Spring Framework 扩充了 Groovy、Messaging、Webmvc、Tiles2、Websocket 等功能组件。同时,Spring 还有条升级主线就是适配 Java 的版本,全面支持Java 8.0,支持 Lambda 表达式等。随着 RESTful 架构风格被越来越多的用户所采用,Spring 4.x 也提供了 RestController 等注解新特性。

  • 2.5 Spring 5.x

软件技术更新换代非常迅速,稍不留神就可能落后于时代,Spring 5.x 紧跟 Java 相关技术的更新迭代,不断适配最新版本的 Java,同时不断重构优化自身核心框架代码,支持函数式、响应式编程模型。我们说历史有其必然律,曾经屠龙的勇士终将变成恶龙,近十年的升级演进让 Spring 越来越强大的同时也变得异常复杂,曾经靠轻量化、易于使用等特点战胜了 EJB,现如今却变得跟 EJB 一样臃肿了,Spring 能否挣脱这个历史的必然律吗?

  • 2.6 Spring Boot

老兵哥是从 2.x 开始加入 Spring 阵营的,期间跟随 Spring 的升级演进一路走来,对它还算是熟悉了解的,这背后沉淀着十年左右的背景知识及使用经验。但对于刚刚参加工作不久的新人来说,Spring 显得太庞大、太复杂了。任何专业技能的精进都离不开长时间的学习和实践,但现实告诉我们,新人才是大部分企业中应用开发的主力人群。能否适应环境变化满足这些新生力量的诉求,将决定 Spring 能否继续稳坐 Java 应用开发框架的头把交椅。

老兵哥近两年在公司内部推广微服务架构,微服务的实现方法有许多种,但关键要从用户视角出发。现在九零后是主力开发人群,完整的 Spring 技术栈对他们来说挑战太大了,他们缺乏足够的动力学习如此繁杂的技术。这时候我们必须要从技术视角转换成产品视角,了解用户的真实想法,降低他们学习使用 Spring 的难度。

在这个关键的时间点上,Spring 不忘初心,重新回到轻量化这个出发点上,采用约定优先配置的理念对复杂度做了封装,对用户屏蔽了许多实现细节。就像计算机的芯片技术异常复杂,但普通用户不需要懂太多电子电路知识就可以使用,现在新人们也不要掌握太多背景知识就可以使用 Spring Boot 做开发了。这是我们技术人普遍缺乏的产品思维,经常碰见以复杂炫技的技术人,再牛的技术,如果不能被更多用户使用,那也终将被淘汰。产品思维就是站在用户的视角看问题,往用户方向多走一步。对于如此大体量的 Spring 来说,这不啻于涅槃再生。

考虑到我们每个人的工作学习情况不同,平时遇到的问题也不同,本文内容无法覆盖所有人遇到的问题,欢迎大家留言提问,关注「 IT老兵哥 」,赋能程序人生!

本系列其他文章索引如下:Spring 核心技术与产品理念剖析(下)

posted @ 2019-12-08 13:22  IT老兵哥  阅读(963)  评论(0编辑  收藏  举报