序言
玄之又玄,众妙之门。
--《道德经》
Framework 看起来很抽象,理解一个具体的Framework,通常由具体的文档开始。但是有没有想过,它为什么这么设计,它是怎么抽象到这个层面的。Framework 的演化历史又说明了什么。我对这个的好奇其实比看具体的调用方式更感兴趣。尤其最近两年做Platform的迁移,必须对framework进行横向和纵向的对比。不得不强迫自己思索这个问题。Framework 试图表达什么,设计Framework背后的规律又是什么。这个问题其实很难说清楚,世间无我又处处是我。《大涅盘经-第十二》说人生八苦,求不得最苦。我的水平还没有到泄露天机的地步,只是如《诗经·小雅· 车辖》所说,高山仰止,景行行止,虽不能至,然心向往之。
Framework是什么
在Java语言开始阶段, 开天辟地,万物初始。Java世界还是出于鸿蒙初始阶段,各种java 应用随心所欲。天道不显,妖魔横行。 在整个社区没有明确说法的情况下, 企业开发平台自然呼唤统一的法则。那么我们看Framework,其实就是java 世界的运行的规律,也就是java 世界的道。
从这个角度看,Framework 团队某种程度扮演着上帝的角色。只是这个上帝确实不会掷骰子。天地不仁,以万物为刍狗。这并不是说天道无情,而是说Framework无差别对待,一切都是按照设计的规律执行的。道可道,非常道,名可名,非常名,对大部分用户来说,说不清楚没问题,只要在术的层面会用就可以了。 但是作为天道厂商, 这个道必须要说清楚讲明白。
上帝不是谁都能当的,想要做Framework, 入门的标准最低也得触摸到道的边缘。达不到怎么办, 只有找Framework的得道高人不停的学习呗。Framework的学习不像写一个app,道路千万条,能用第一条。规则定错了,那是千千万万的用户都要遭殃的。路漫漫兮其修远兮,吾将上下而求索。有这样的精神,才是合格的Framework 的掌控者。
Framework 有高下,没有好坏。任何一个Framework的出现都是时代的呼唤,环境的要求,满足了当时的系统需要。脱离实际情况去评判Framework,基本上就是耍流氓。经常听到这个太烂了,那个也不怎么样。 诚然,从用户的角度上,江山代有才人出,一代更比一代强这是公认的。但是作为Framework的守护者,我们不应该有这样的情绪,仔细分析这些Framework的内容,每个Framework都有可圈可点的地方。每个框架都代表了那个年代的最高生产力。有继承才能有发展,我不赞同Framework的人只在最新的上面流连,对于过去没有致敬。
薪火相传,才能继往开来。这并不是拆迁的要求,而是传承的需要。
Framework 解决什么问题
很多觉得Framework没啥东西,又枯燥又学不到东西,最好能搞点时髦的,有领域知识的事情,理想的的职业方向是架构师。我听了总是微微一笑。并不是道不同,不相与谋。 而是虽然是风月同天,只可惜我们山川异域。
想当架构师,画画PPT。轻松而又愉快。这个系统不好,不是我设计的不好,而是下面的团队水平太差,不能够理解我的意图来正确的实现。至于客户,阳春白雪的理想真的需要下里巴人来参与吗? 我空负满腔柔情,只是你永远不懂。世上真有这么轻松愉快的事情吗?实践是检验真理的唯一标准,是骡子是马总要上磨盘前溜溜。基础学科的严肃性就在于它不能够掺水分,好不好用用户和业务是评判的唯一标准。从公司层面,最大的要求是,我花了钱,你能不能让我听到响。
设计一个Framework,要干点啥。简单的说就是要解决系统的运行规则。具体到实际,就是对边界的设计。每个人边界不同,设计出来的系统千差万别。举个现实生活的例子,生死是一个永恒的话题,宗教对生死的边界是轮回,死是生之开始,死亡不是一件可怕的事情。 对于大部分无神论的我们来说,死亡是最大的恐怖。那么自然规范到行为和做事情的范围,都有明显的不同。做Framework的人眼界要高,范围要宽,同时身段要低,思考要勤,这样才能做出合适的产品。
在系统的规则下,道生一,一生二,二生三,三生万物。各种应用能够自由发展,各种业务有无限可能。 科学尽头是神学,神学其实就是哲学。Framework也不例外。要做Framework,就得解决哲学三个基本问题“我是谁, 从哪里来,到哪里去”。历史总是在不断的重复上演,我们解释不同事物的历史,可以用同样的治史观。人类历史上的认识同样可以应用到Framework的理解当中。同一段历史,只是演员不同而已。
我是谁
这个问题主要来回答生产资料和生产关系的问题。在1845~1846年马克思和恩格斯合写的标志历史唯物主义创立的<德意志意识形态>中,形成了人类社会的经济基础和上层建筑的概念。在这之前,黑格尔也有类似的表达。黑格尔和马克思都是历史终结论的支持者, 但是马克思认为未来是资源无限的,因此可以按需分配,而黑格尔是认为资源是有限的,因此是按劳分配。交换资源。这样说明,不同的人看待问题的角度不同,自然出来的体系不同。那么对于Framework,面临的问题也是一样。
我有哪些资源
对于Framework, 自然就是源码,配置文件,Metadata,外部提供的library 等。有了资源,还存在你怎么看待他们的问题。如果你把这些想象成从事不同工作的人。对应人类历史,从奴隶社会,社会分为不同阶层,到现在社会,人人平等。 这中间对人的看法实际上是不断演化的。事实上从Framework的演化历史上看,历史也是惊人的相似。最开始的时候,源码,配置文件这些就是不同的。他们看山是山,看谁是水,用到就用不同的逻辑和代码把他们加进来。 最多提供个Util 方法。到了Spring, 对于资源的看法有了进步。所有的配置文件,配置类, 工作类 对于Spring 都是BEAN,对于Spring 来说并没有不同,规则的运行实现了统一对象。这是框架的巨大进步。Spring 刚出现的阶段,基本上所有的文章提到Spring都是IOC、AOP。这确实有好处,但是这并不是说以前就没有,用纯JAVA 代码也同样可以IOC、AOP。在我看来,Spring最大的创新就是在于政治制度上的创新,让Framework能够支持App owner用同一类对象去思考问题。经济基础决定上层建筑,上层建筑也是经济基础发展的最大保证。这也是Spring 能够蓬勃发展的最大内因。
我这些资源怎么安置
对于自开发的资源, 一个project 源码是什么样的结构,配置文件放在那里, metadata(pom.xml , raptor_app.xml) 放在那里。这个project 作为应用如何build, 这个project 如果作为library 怎么build,并如何被人引用。对于第三方资源,我们怎么引用,如何定义接口规范。对于老的平台,他的有自己的一套资源安置规则,也有自己的发展历史。它把source code和library分开, 在projectclog 和 libarycatalog 来定义这些资源的位置。App project 必须在公司内部系统中才能被build,并不是一个开放性的概念。也没有利用到社区的优势。后续的Spring,SprignBoot投向Maven 这个开放性资源平台,在资源安置方面也进行了统一。Maven 最大的特点是和谐了内部和外部,而不像老的平台只是统一了内部。Maven保证生产资料在java 世界有了统一的物流平台,让生产资料在Framework 的管理下,通过版本的控制,能让这些对需要的应用实现快速分发。从这个角度讲,是开源社区带来的红利。这也是企业越来越拥抱开源社区的原因。物流的统一,不仅快,还包邮。让好的Library好的项目能够迅速蔓延。极快的推动了社区的发展。
我怎么分配这些资源,尤其是自开发资源
生产资料所有制,是生产资料生产关系首要的决定性的部分。人类的历史上,分配制度也经过很多阶段。其中从氏族部落的公有制慢慢的都转向了私有制,是一个重要锚点。以此类比,Framework的演化也是一样。Framework 最开始是共享原则, 你的就是我的,我的就是你的。那么是项目/library/源码/Metadata 是全局共享的,这个体现在很多方面。有些是一个源码很多package都来自于不同团队,有些是这些app可以打在任何一个release的部署单元,造成同样的service 分散在不同的地方。 有些是不管这些配置文件我用的到用不到,我反正所有的都用同一份,有冗余也在所不惜。在这样的情况下,大家是一条绳上的蚂蚱,紧紧的团结在一起。赢了一起狂,输了一起扛。很多老的平台都是这样的思路,这样有个好处,在规模比较小的创业初期,产品测试发布很快。需要强调的是,在2000年那个年代,这是很流行的思路。 初期的google,facebook, paypal 他们的产品都是全code base 编译。
但是随着外部用户越来越多 ,系统越来越复杂,组织分工越来越精细。公有制分配已经造成了生产资料和生产关系的矛盾。共享资源在业务响应,系统效率和耦合性上的问题越来越突出。Framework也慢慢走向了私有制。私有原则,强调的独立性和灵活性。你的就是你的,我的就是我的。特点是自我驱动,自我满足,互相交换。从而满足快速增长的业务和系统要求。最近几年,微服务的兴起,也说明这个方向。从设计模式上讲,开闭原则也说明了同样的道理。去耦合,高内聚现在已经成为现在方向。具体的好处,这里就不详细展开了。可以联想一下1978年联产承包打破大锅饭对中国的影响。
从哪里来
这个问题来回答Framework怎么用自己的规则利用生产资料来构建世界的。在心理动力论中,本我、自我与超我是由精神分析学家弗洛伊德之结构理论所提出,精神的三大部分。1923年,弗洛伊德提出相关概念,以解释意识和潜意识的形成和相互关系。那么在Framework 构建世界的时候,他其实也要构建本我,自我,超我。
构建本我
本我主要是Framework本身所需要的容器的构建。不同的Framework,所需要的容器不同。
容器一方面提供了如何辨别生产资料并分析生产资料的依赖关系的能力,另一方面对生产资料进行初始化并提供安居场所。
对于老的框架基本上他并没有特别的容器,只是利用了JVM的本身这个容器。
这就决定了它只能用Java原生的方式来构建类。因此在老的框架中, 用单例模式来定义依赖关系(简化代码定义),如果不这样就需要自己构造一个对象,并且调用对象的方法,如果没有内在框架的支持,这样定义是非常麻烦的。JVM 本身没有办法维护静态方法和单例模式的依赖关系,最简单的办发是在构造函数里把依赖构造,就是说只能通过代码的的规范来表明关系。先注册依赖方法,再注册自己。这种方式促使依赖的上一级的依赖关系定义只能单例方法的构造函数中。这是世界观造成的现象,能用但是要求很高。
用单例方法最大的系统问题是,这种方法要求很高。因为用静态构造函数描述依赖关系时候。这个依赖关系受到两个因素的影响。 一个是程序定义的顺序,一个是类加载的顺序。这两个综合作用才能最终决定一个构建的真正顺序。因此能够在任何情况下,定义的关系都能保证正确构建的前提是这个方法是幂等的,更通俗地来说是无状态的。如果是有状态的,就意味着有了依赖。如果我不能保证这两个因素的先后,我就不能保证我的依赖永远发生在我之前。事实上Java保证不了这两个因素的顺序。
这就要求每个程序员在写关系注册的代码的时候必须时刻牢记,我只是明确关系,不能有任何依赖逻辑。 事实上,这个对程序员要求太高。除了Framework的开发者,大部分人不会关注生命周期。
Spring 的出现明显进步了很多,由于它和佛教的教义相同都是众生平等,也都需要为此打造自己的极乐净土。因此他在JVM的基础上,又有了自己context。同时它提供了依赖关系注册机制,用户不在需要自己写code注册。不论是定义在xml 里, 还是用了annotation,用户的依赖关系定义可以摆脱静态构造函数。context 注册自动扫描建立关系,然后通过Bean Factory 把所有的资源按照依赖关系生成Bean。 这个过程就是Context.refresh 里所做的内容。抛开技术原因,你觉得这像不像佛教经常宣讲的,静心听禅语,佛度有缘人。
只是在Spring boot里做了很多增强。除了有code 基本的依赖关系定义, 还可以有annoation 的依赖关系定义。在Bean 的创建过程中增加了conditional和profile的概念。需要强调的是,在Spring的世界里,context 可以不止一个。可以有各自的道场。 比如spring boot acturator 的实现,和spring boot batch的modular job。
构建自我
自我是除了容器之外,开始装入企业应用的的Kerenl, 这些Kernel 的Component是构成了能在业务线上跑的公共服务, 每个framework提供的方式也是不同的。这些Kernel Component 是 其他的基础设施,没有这些基础设施那么其他的也不能正常运行。所以他们要进行第一批初始化。就是房屋的水电煤,虽然不直接依赖他,但是我们都需要他。
在原始平台的kernel构建没有特别的地方,它只是靠代码定义在最底层的依赖上,保证他能被最早初始化。
在Spring base 的初始化过程中,这些kernel Component 初始化顺序依赖于spring DI 的关系。同老的framework相比,这样能绝对正确的Kernel 初始化顺序。但是缺点也是显而易见的,必须把所有的Kernel Bean 显示加入依赖。同时Spring 在不同的statck ,都需要把这个初始化逻辑重新实现一遍。 并没有统一的方式,在同步的问题上,经常会造成非主流 Non-Web (如Batch)的变化更不上主流的Web 的Framework 变化。这点Batch 团队要花大力气进行跟踪和同步。从这点上讲,Raptor 其实还是没有真正实现自我构建的平等,自我和本我还是有矛盾的。
只有到了Spring Boot 才真正实现了WEB和NONWEB自我构建的大一统。 同时对于Spring 并没有“自我”的概念,也没有这种需求:“我没有定义依赖关系,可是一批Kernel Bean 必须先初始化”,我们可以做些增强,在Spring Boot 初始化是来强行扫描特定的annotation 的bean 来实现kernel 的初始化。 从这个角度上,如果说生产资料统一成Bean是从政治制度上对生产关系实现了保证, 那么本我,自我统一就是从法律条款上对生产关系再次进行了夯实。
构建超我
超我是Framework 如何和别人合作获得超能力。一个人的能力有限,你只有借助团队的力量才能把能力发挥到极限。大家经常听到的道教隐宗中的太乙天尊《太一拔罪斩妖护身咒》有一句耳熟能详的话,“天地无极,乾坤借法”。说的就是这个道理。 Framework其实他有两个合作对象,一个是内部的用户,一个是第三方的用户。无论是是什么用户,其实他都一下这几个需求
- 我的定义和构建如何被Framework 发现
- 对于已经存在对象的构建我有没有办法运行时做些修改或者增强
- 我有没有办法在kernel 初始化和App 初始化之间自动注入我的逻辑。
- 我要能知道Framework 现在运行到什么阶段了。我有没有办法在这个阶段做一点我的事情。
- 我和别人合作的时候能不能只针对接口编程。
- 我能不能把我不要的功能拿走,我只挑我需要的功能进来。
- 我能不能统一WEB 和NON-WEB, 让他们在统一的框架里运行。
Sprign boot 在超我阶段统一了web和非web,统一了外部集成协议。在本我,自我,超我都实现了统一。因此最先进的Framework 它当之无愧。它可以横跨stack,功能可大可小。有了Spring boot, 微服务、Spring Cloud 才有了基础设施的保证。
到哪里去
Framework 最终要支配Java 应用被使用。每个Java 应用都配上有个好去处。那么首先面对的是打包的方式以及打包的方式对整个生态的影响。

可以看到Spring Boot统一了打包类型,一个Jar 包就是独立完整应用。 这个设计的意义是深远的。他自满足结构为Severless,微服务 等各种应用提供了基础。
古人认为天人同类同构,物我同一。天地万物同是一原。这也是爱因斯坦一直孜孜不倦去寻找统一场理论的原理。无论从宏观还是微观,大道不独行。Spring Boot哲学的三个问题是都实现了统一的哲学观,就算是不谈实现。他也应该代表着更先进的Framework。天之道,损有余而补不足。 其中含义无非是平衡统一。 Spring Boot目前来说是做的最好的Framework。
理解Framework的意义
明白了Framework要解决的问题,有什么意义。最常见的就是我们做拆迁了。如果让Spring 的App 迁移到Spring boot 的App, 你需要怎么做?如果要求Application的用户不改一行代码,而由framework 提供一个方案改怎么做?
从我个人来说,本我是不能修改的,修改了就不是这个framework 了。 那么我会从三个方向考虑
- 自我的Kernel:底层我们解决所有Framework 的差异。 只要解决我是谁,我从哪里来的问题。这个底层对于所有的stack 都是适用的。他构成了工具平台
- 自我的Stack适配。
- 超我的App。如果第一层,第二层的问题都解决了,那么App遇到的问题一定是第一层,第二层解决不了的问题。到这个时候,这些问题是跟stack 无关的普遍问题,可以稳定重现的。那么我们就可以形成稳定的知识库,也不需要每个人都有很深的stack知识。
而如果你不能从这三个层面解决,你可能每个stack 都有一拨人, 同样在底层的一个问题,表现不同的stack 会有不同问题, 大家疲于奔命,而又得不到根本解决。更重要的是,你不能进行知识共享。
如何学习Framework
每个人的学习就像仙,从练气、筑基、金丹...不论哪个阶段,都希望自己道飞升。只是Framwork的学习,每个阶段对道都有不同的需求。如何让自己能够得道。在我看来,没有什么更好办法,就是要熟悉每个Framework,把对Framework 的认识应用到每个问题中去。需要强调的一点,我们不能放过每个问题,每个问题都要找到真正的原因。日积月累,相互印证才能有所收获。如果你经常能解决一个别人百思不得其解的问题,那是你积累印证的多了,并不是你有什么秘藏。众人不知谓之秘,众人不见谓之藏。实际上道理都在哪里。学习Framework 是枯燥的,要受的了寂寞。同时Framwork的修改也是要慎之又慎。《地藏王菩萨十轮经》称赞地藏王,安忍不动如大地, 静虑深思如秘藏。这个和我们Framework的团队很像,平时并不是显山露水,但是每个修改都需要静虑深思。即使我们限于水平不能完全做到,但是明心见性,心诚自然会灵的。《庄子·天下篇》的内圣外王说的也是这个道理。