我对Web MVC框架实现原理的思考(第一篇)

虽然从软件架构的角度,我们需要权衡取舍,需要克制在系统中过分追求技术。但是对于每一个有理想的软件工程师,造轮子的情结是永恒的。各种各样的轮子,始终是软件工程师挑战自我的必经之路;web框架无疑应该是一个比较好的开始,我自己也曾经试图造一个精美的轮子,但是始终实在业务发展压倒一切的创业中,只能是点到为止。

所以,在有机会再次完整的去造轮子之前,通过自然语言,来整理一些思路;如果用画画来比喻,就是试着在画竹子之前,先整理一下自己胸中竹子的形象。Web框架是一个好的选择。

首先是Web框架的定义。Web框架应该是使用某种特定的语言开发,运行在服务器端,利用特定语言已经提供的http库或者http服务器完成自己的工作,处理用户请求,返回主要是Web页面在内的资源。Web框架应该是以编程语言API的形式出现;提供一套契约设计好的脚手架,一些实用工具。

理论上说,支持Http协议的Web服务器应该Web框架要讨论的范畴,但是根据具体的架构和技术选型,可以是跟web框架的定义或近或远的。下面是我自己使用过或者有印象的一些主流Web框架:

  1. PHP语言:CodeIgniter、ThinkPHP、Laraval;php的框架,http服务器,基本上是不包含在Web框架核心中的,Apache httpd或者php-fpm+nginx处理请求响应两端,web框架不需要考虑端口监听,这个相当于是一种解耦和。
  2. Node.js:Express,没有接触过太多其他的框架,在node.js的架构下,node.js本身是有完整的http客户端和服务器端能力的,我们完全可以用原生的node.js服务器端API,处理request,然后完成自己的业务逻辑,之后返回用户要请求的数据。
  3. Java:Spring MVC、Spring Boot;实际上Spring Boot框架下,严格的Web框架还是Spring MVC;Spring Boot通过内置的Jetty或者Tomcat来提供Http服务器的工作。在Java领域,应该可以有两种不同的思路,一种是基于Tomcat,Jetty作为Servlet容器,Web框架对Servlet进行封装,并提供自己的API,开发人员在此API之上开发;或者还可以使用Netty自己来编写全功能框架。
  4. Python:Django、Tornado;Django提供了脚手架支持,集成了一套功能强大的ORM,可以通过代码生成器,从代码直接创建数据表。
  5. Ruby:rails;做过简单的尝试,没有机会深入使用过,听说rails的模式是敏捷开发最初的利器。

Web框架的组成

一般说道Web框架,我觉得应该包含以下一些组件或者模块:URL路由、MVC模式支持、特定的html模版语言、ORM、脚手架或者代码生成器、配置管理。有些组件是必须,有些只是可选的,并不一定需要在框架中默认提供,开发者可以根据自己的需要自由集成需要的组件。

URL路由和控制器

url路由,是web框架的一个核心组件,资源的绑定,通过路由来配置。mvc的控制器层,在运行时视角,基本是从url路由来调度的。

说到路由,首先是对http服务器的理解,web mvc框架层,代码层面上,有各种不同的资源文件,各种不同的链接,函数。通过逻辑上的分解,降低了系统复杂性,将系统各层面的代码解耦到了不同的逻辑单元中。但是回到HTTP服务器的机制,其实物理上,http服务器都是单入口点,监听在特定端口的http服务器进程,所有的http请求都是从入口点程序开始执行的,入口点首先是对tcp套接字的封装,有的web框架会直接内嵌完整的http服务器,全功能的可以作为http服务器来运行,有的需要借助容器或者是纯web服务器来配合完成工作。

Python Tornado框架

Tornado的原理跟nodejs差不多,入口程序调用http api,开启监听在绑定端口的套接字,框架底层嵌入的http服务器,会处理网络报文,将http协议的header解析出来,并且以api形式可以提供给基于框架的应用调用(这个地方语言和框架的边界不是十分清晰,语言底层一般会提供,框架可以自己在对api进行一层包装,提供自己的api)。

在web框架中,url路由,基本上是和MVC的controller层紧密协作的,路由负责控制对象的初始化和调用。一般控制器的原理都是通过框架提供的抽象类来封装一些公共的方法,然后子类实现具体的接口的方式工作的,将子类定义的公共方法,作为特定url指向的资源。

在tornado、express、laraval提供的url路由类型机制里,都是通过开发者自己配置维护一个路由表的方式,将url链接,跟静态资源,或者MVC的控制器绑定起来。在请求到来的时候,单入口执行过程中会有一个路由解析的过程,提取出url字符串,对字符串进行解析,然后跟路由表进行比较,使用字典是比较好的选择,然后根据不同语言的特性,可以有不同的方式,实现对路由表指向的特定资源的代码调用。

底层运行时,存在一个路由到控制器的运行时路由表,对于web框架来说是必须的。除了开发者可以直接配置的统一路由表的实现,还可以有其他不同的机制。

几种不同的URL路由机制

  1. 完全基于契约的CodeIgnitor模式,约定路由加载控制器的特定目录,然后根据控制器的命名和共有方法的名字,来跟请求的url进行匹配。这个是基于php的语言特性支持,能提供的一种优雅解决方案。
  2. 通过注解实现的,预加载路由表方式;Tomcat容器的在加载应用的时候会在加载阶段就加载所有的类,不同于PHP的运行时动态加载,所以需要占用更多的内存。Spring MVC是基于Java的Servlet,Tomcat是运行Servlet的容器;个人的观察Tomcat容器默认会提供Servlet、jsp等Jar包形式提供的类库。不过在注册特定uri资源的入口点,资源请求到来的时候,动态执行路由指定的控制器上,是一样的。
  3. 上面主要介绍的,显示的用专门的路由表,由开发人员自己配置的模式;这种方式的话,个人感觉比较容易维护路由表。

HTML模版语言

理论上说,对于控制器层而言,其实html代码,就是最终将字符串拼接起来,在对应需要服务端数据的地方,拼接上对应的存储数据的变量。这种输出的过程当然是比较原始的,早期的web或者JSP可能存在着大量这种混合式的调用,在逐步分解出jsp的过程中,会在jsp文件中,以html格式做主框架,然后任何需要数据的地方,直接调用底层的数据查询和处理代码。这种方式,逻辑是很混乱的。
有了MVC,我们会在控制器层,完成所有数据查询和组织,还有计算过程,以model的方式,将简单的Map、List、还有直接对象的方式,将数据变量绑定到Model中。这样View层的html模版中,只需要考虑怎么展示Model绑定的数据。
一般框架都会自带或者内嵌一个模版引擎,在控制器层,提供某种机制,将变量绑定到模版中。而模版中会提供很多处理数据显示,进行格式化输出,还有数值计算的使用函数,都是通过模版引擎支持的特定语法实现的。

freemarker时间处理

脚手架和代码生成器

这个层面并非是必须的,express、rails、django,都是通过各自的包管理工具,可以直接初始化创建该框架应用的脚手架。在脚手架领域,基于npm有专门的Yeoman,可以自定义各种脚手架。

脚手架Yeoman

一般来说,像django和laraval,都提供了migrant工具,就是一种代码生成器类似的概念,可以直接将配置文件或者定义的模型层代码,生成数据库的表和字段。另外他们还提供了方便的代码生成器功能,直接通过命令行下的命令就能快速生成控制器的代码。
另外还有与业务逻辑更紧密一些的ORM层代码生成器,离web框架的核心有一定距离,例如针对MyBatis,我们可以使用官方的mybatis-generator,编写配置文件,直接从数据库结构生成DAO层对应的一些CRUD代码。

结语

理论上说,提供数据访问支持,也是一个全功能web框架通常会提供的组件,不过数据访问,可以专门在另外一个主题讨论。本文主要就讨论一下我对MVC、URL路由、html模版、还有脚手架的一些理解和思考,试着理清自己的思路,后续,肯定会最终作为自己的一种能力提升的挑战去造轮子。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容