首页 > 代码库 > 框架的艺术

框架的艺术

  • 框架的意义

    框架存在的意义,必须在实际生产中体会。每一门技术和框架存在的意义都是因为现实的需要,需要解决某一个问题,某一个场景。最近读的一本书,《淘宝技术这十年》,淘宝一开始也不是集成了什么分布式系统,一样是LAMP的架构。技术是根据需求场景和业务而发展的,比如一个学校的一个年级,入学人数只有500的时候设置10个班比较合理,一旦人数增长到了1000(业务增长)之后,发现如果10个班(服务器)每个容纳100个学生(并发)是一件比较吃力的事情,那么就必须增加班级了(扩容),那按照之前的数据一个班容纳50名学生是一个良好的运行环境,这样就需要20个班了。但是哪个学生进入哪个班级(URL分流,负载均衡)需要通过考试或者平均来分配。技术的发展强依赖于现实业务的增长,而技术的发展带来了业务增长空间。

    开发框架,是为了生产者在这个生产模式下极大的提高生产效率,一个好的、通用的开发框架必须囊括了产品所需要的通用功能,比如某公司有统一的商标,则这个商标的生成不需要投入劳力来反复生产。包装需要统一的材料,所以在材料方面尽量使用统一采购接口。任何一项有需要复用的功能,在框架中都应该得以实现。而投入人力的方面,则集中精力的解决业务问题,也就是说产品的功能、产品的包装设计等等无法通过计算来实现泛型设计的部分。Spring带给我们的理念就是,大量重复而臃肿的代码需要统一地实现以减少人力在这方面的投入,使得他们更加专注于他们的核心业务(AOP)。在企业里面的部门有人事、财务、技术等等,他们的工作是互不交叉的(低侵入性),如果一个公司的分工是十分混乱的,那么这个公司的员工肯定是低效的且这个公司是发展缓慢的。

    我们在为掌握的“工具”(Struts、SpringMVC等)而感到激动地时候,更多的应该思考这些“工具”给生产带来了多大的便捷,思考它们的“位置”(控制器、持久层等)。这些技术实现,是为了组成某种产品的零件提供通用的解。MVC的架构实际上就是描述了软件业里面产品的通解:如果一个网站不是MVC设计的,那么它是什么呢?动态网页技术肯定是数据库的读写应用,前端的变幻无穷依然需要控制器去调用模型生成需要的页面。或许我们已经被MVC深深的影响了,如果让我们想一套新的方案,真的可能想不出来更为简洁的了。我相信,即使换了一门语言,它一样有MVC,如果没有,它的设计并不会比MVC更优,有可能杂乱无章。

    重道不重术,是吴军老师在《数学之美》里面给我的启发,练拳要练功,在写代码的同时必须注重思考这些逻辑背后所支撑着的真理。饭前和同事聊天,他说实现前端效果的需要变化需要很多不同的技术,学无止境。窃以为他没有点到本质,技术的变化不是因为需求的变化而变化,我们学习不是学会实现业务的种类(术),而是学习将所有业务都统一实现的逻辑(道)。在我们的教学过程中,特别是数学更有这种指导意义。为什么实数可用x来表示,为什么数列存在通项公式,为什么抽象函数可以表达所有的函数等等。这种由n=1得到值并推广到n得到公式,相对于某个n值来说它就是道,而推导公式的方法对所有公式来说它也是道。越是本质的东西越存在不可替换的特性,所以为什么会有:练拳不练功,到老一场空。时间会把术泯灭,而道却永恒存在。

  • 技术的思考

    关于技术,种类纷繁不胜枚举,每次从阅读官方文档到写demo然后投入生产这一过程的不断重复,期间总会产生一些感悟: 我们总是在学习相似的技术

    就Java而言,它的语法基本上囊括了计算机应用所需要的功能:面向对象、文件读写、网络通信等。它的网络框架无论是SSH、SSM或者其他的如JFinal,它们依旧是实现了相似的功能并且有着同一目的:为了加速生产效率。在Struts风靡一时的时候,并未诞生SpringMVC,这个历史进程中可以得到的结论是,业务量并未提升至需要新框架的地步。而在日益增长的互联网服务环境下,SpringMVC凭借着高开发效率低侵入性还有那特色的注解开发赢得了市场的青睐。任何一门技术总是在效率市场的竞争下不断推陈出新,而它们的目的与意义无外乎解决必要功能之后,提升生产效率。

    对于技术的选种与学习,结合我的经历来谈,在初始学习的时候要尽可能的细致。因为相似的特性存在与不断更新的互联网技术中,在你选择的领域中技术的进化所增加的新特性中,肯定是基于旧框架的功能添加。无论套用多么新潮的词汇或者是取了个让人眼前一亮的名字,在学习的过程中对于它的考察必须基于:历史、特性、解决场景这三个方面来理解和吸收。举个例子,分治法这个算法的特性,就是具有子问题不相互依赖可以分别计算最后合成为总问题的解这么一个特性,所以基于这个原理,具有这个特性的问题就可以使用这个思考模式,如hadoop中一个demo词频统计,因为英文每个词会间隔一个空格,所以它们的统计上是属于相对独立的子问题,在hadoop这个框架下可以轻松统计,而中文的拆分就需要分词器,因为每个字可能和前一个或者后一个有联系生成一个词。

    所以,对制造框架的技术选种,关键是你要解决什么样的问题和场景。对于1000人用户的网站不需要服务解耦,对于编译不到1分钟的项目不需要使用dubbo,对于传说中的修改一行代码编译一个小时的项目需要考虑分布式。花俏的技术不是生产所信仰的宗旨,基于特性的思考才是一个工程师需要具备的素质。

  • 小型框架的诞生 

    当今web服务疯长的互联网市场,快仍然是一个不变的要求。如何更快,是架构师们每天的思考。开发框架的诞生通常是结合生产环境而做的设计,对于1000人以下的系统,应用于公司某部门、政府某事业单位、教学等领域,使用传统的MVC模式构建的三层结构是十分足够的。面对大量用户的互联网的需求,分布式和微服务等架构的Web应用随处可见其MVC的踪迹。因此书本上并不会过多的介绍具体设计分布式系统的架构,而只是把概念介绍了一遍。

  1. 三层架构的意义

        如前面所说,框架的意义以及现代框架设计的原则就是让代码更专注于做自己的工作。MVC(Model层、View层、Controller层)模式的设计很符合软件工程的设计美感和框架设计原则。

    技术分享

        如上图架构,视图层专注于向用户呈现计算产生的界面,控制器层负责调度视图层的呈现和从业务层中获取数据,业务层则负责数据库事务和调用模型层进行计算。一个小型网站的访问就是用户从浏览器中输入url,这个url在纯粹的Web应用中就是直接访问到控制器中,由控制器经过计算后吧动态页面通过http协议返回给浏览器,浏览器通过标记语言组成页面。

  2. 根据特性而应用的框架

        在Java Web领域中,未见其人先问其声的当属:SSH。在众多框架中脱颖而出并且占据了MVC市场的三大框架,依据特性来分类的话,对于视图层和控制器层:Struts2、Spring MVC等,对于持久层(Service层):Hibernate、MyBatis等;Spring作为解决依赖关系和精简项目代码的框架而存在,它负责兼容多方框架、构造Bean工程、设置切面、统筹声明式事物等功能,是一个十分优秀的框架“润滑剂”;

        Java Web容器中,存在Tomcat、Jetty、JBoss等免费的Web服务器。它们都是Servlet的容器,遵循JSP规范。源生的JSP技术中,以Servlet为控制器处理Http请求并返回Http响应,页面上也可以通过嵌入Java代码做成动态Web页面。但是由于这门技术的可维护性比较差(主要是页面JSP代码),所以现代大多见的是El表达式、ONGL表达式或者是前后端分离后JavaScript做的数据处理。

        Web应用的本质就是对持久层的操作,所以持久层的存在是十分必要的。源生的JDBC编程可以实现全部的数据库交互,然而繁琐的JDBC代码始终会拖慢开发的效率。为此诞生的ORM框架Hibernate致力于处理对象和数据表的映射,而另一个备受欢迎的框架Mybatis却不是以对象映射而擅长,Mybatis的框架特性是对Sql定制而闻名的,对有Sql优化经验的人来说它是个很好的选择。

  3. 快速开发架构

        如数学公式能定义一类数集映射一样,好的架构应该把人的劳力控制在一定范围内,在程序员对业务进行设计的时候不需要思考构造架构的组件。对于小型网站而言,笔者的经验总结它通常有两个入口去访问这个网站。某些控制器是return page的而另一些是resturn json data的。所以有些时候你访问一个网站失败了,会在页面上打印{...}这种数据。对于控制器的设计,架构应该提供页面规范和接口规范,即 域名/Web应用名/接口(页面)这样的访问形式会返回页面或者是Json数据。采用当下最流行的RESTful架构风格,接口只需要根据url参数来进行相应的数据返回。比如博客园的https://i.cnblogs.com/用户名/p/(id名)则是从文章数据库中查询相应的文章,但是它并不暴露所传递的参数,与平时常见的GET请求有所区别(如果是常规GET请求:https://i.cnblogs.com/用户名/p?id=...)。

           Spring MVC良好地提供了一种RESTful的风格的接口编写。

    技术分享

    

package Test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import Common.Controller.OutputStringController;

@Controller
public class Hello extends OutputStringController{
    //接口形式
    @RequestMapping(value="http://www.mamicode.com/Hello",produces="text/html;charset=UTF-8")
    @ResponseBody 
    public String sayHello(){
        System.out.println("访问了Hello!");
        return failure("失败");
    }
    //restful接口
    @RequestMapping(value = "http://www.mamicode.com/start/{name}", produces = "text/html;charset=UTF-8")
    @ResponseBody 
    public String start2(@PathVariable("name") String name1) {
        System.out.println(name1);
        return "start";
    }
}

 技术分享

技术分享

  • 服务端架构设计

    针对小型网站的设计,重心依然放在与数据库的交互和呈现页面给用户这部分上。而变化多端的业务程序必须由人力来完善,在处理事务的过程中,必须保证数据从用户到数据库的正确性,所以把事务应用于Service层。在用户操作数据的过程中,每一个结果必须具体告知用户(是否已存储数据、数据是否合法、是否发生了异常而导致数据有损)。用户登录后台检查录入数据的页面必须友好易懂,在页面加载过程中等待的时间尽可能控制得越低越好,所以在表设计的过程中以及SQL的编写必须再三斟酌。

技术分享

    网站的配置文件尽可能不去改变,因为一个小小的改变有可能会导致蝴蝶效应。可以更改的部分仅仅是数据库的更换,数据库账号密码等。

技术分享

    网站的公共功能需要根据项目的需求进行完善,对于小型网站的功能可以列举的是:启动自动建设对象和表的映射、启动定时任务、JavaEmail的发送、登录过滤等等。

技术分享

    业务层的设计规范,依托Spring提供的事务模型,如果需要aop再行配置。对于表设计,尽可能使用单表设计,而表关系尽可能使用程序逻辑来实现,事务的设计笔者采用下图所示。

技术分享

 

技术分享

技术分享

    网页资源在WebContent中,网页一般有静态页面、图片资源、CSS样式、JS代码以及JSP页面。

技术分享

    网页路由采用访问控制器后返回Web应用下级资源,控制器有如下形态。

/**
 * 主页控制器
 * @author ctk
 *
 */
@Controller
public class IndexController {
    @RequestMapping("/index")
    public String index(){
        return "index.jsp";
    }
}
    <!-- configure the InternalResourceViewResolver -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
            id="internalResourceViewResolver">
        <!-- 前缀 -->
        <property name="prefix" value="jsp/" />
        <!-- 后缀 -->
        <property name="suffix" value="" />
    </bean>

    在return的字符串中,会加上前缀jsp/,这样访问接口资源就会定位到jsp包下。

技术分享

技术分享

    如果直接访问页面,则不会加载出样式。如果不想用户直接访问,使用Interceptor过滤掉用户的请求即可。

技术分享

 

  • 小结

    这套框架是从工作中总结而来,虽然在当今分布式横行的环境中可能不具备什么优势,但是经典结构是Web技术的基础,无论如何服务解耦都逃不过MVC的影子。读到书上说的URL分流,其实就是在控制器前加一个负载均衡器,用户访问同一个名字的接口会由中间件选择负载较轻、响应较快的节点返回资源,而在Web应用发展到编译一次半天过去了的情况,则会把Web应用中的Service层解耦。相对独立的Service会形成一个提供服务的中心,提供某种服务(用户资料中心、商品中心等)。他们的信息交互有可能使用到消息队列,一切都是大型网站发展的必然趋势,然而分布式只是拆应用,并没有拆掉他们的本质,对于网站架构,笔者仍然有很长的路要走。

框架的艺术