前言

最近需要开发一个纯API的项目,mlsql-cluster,从无到有,到最后完整的proxy功能开发完毕,只花了四个小时不到,自己不尽小感叹了一把 ServiceFramework的高效。

关于ServiceFramework的诞生

ServiceFramework算是一个古老的,基于Java的web框架了。我印象中应该是我11年的作品,那个时候应该是RubyOnRails正火的时候。我做了一段时间Rails程序员,后面转型做搜索,期间觉得没啥好用的Web框架,于是就开发了ServiceFramework。

极致简约的要求

早年Java语言的笨拙一直是广受诟病的,业务还没两行,代码和配置就已经几百上千行了。首先我们不可能改变这门语言,那么如何做到极致简约呢?自动生成源码的套路肯定不行,用户就天天通过各种命令生成源码去了,而且通常生成的源码又丑又难看,还不敢改,所以我们需要无声无息的为用户生成必要的代码, 并且还不能让用户看见,还需要兼顾IDE的代码提示。那么,应该怎么玩呢? 核心在于两个点,我们后续会展开讲:

运行时代码生成(codegen,功能增强)+ 父类方法签名(代码提示)

极致简约体现在哪

应用包含容器

早年几乎清一色的,代码都是跑在容器里的(weblogic,tomcat等)。在11年的时候,SF做出了一个重要的设计,就是http只是代码对外暴露的一个交互方式,和RPC一样,Web容器只是你运行代码里的一个组件而已。所以SF的启动是这样的(演示代码都是用Scala写的哈):

 
 

就是一个普通的Main方法。大家有没有发现现在大部分Web框架已经都这么干了。

配置文件精简

早年Java领域出现了一个潮流,就是能配置的坚决不写代码,配置可以更灵活,但是它们忘了配置本身也是一种代码(语法受限的语言),反倒增加了成本,所以后面引入了Annotation以及约定俗成。SF设计之初,就只有两个配置文件,一个application.yml,一个logging.yml文件。基本需要配置的很少。核心就是一个数据库配置信息,然后一个http端口。

自动读取数据库配置ORM

个人感觉对数据库的操作很难比SF更简化了(吹牛)。在SF中ORM是无任何配置文件的,唯一的信息就是在application.yml里的链接信息:

 
 

接着你按传统的方式在数据库里建好表,比如

 CREATE TABLE backend
(
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255) DEFAULT NULL,
url text,
tag text,
ecs_resource_pool_id int(11),
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建了一张backend表。然后我要在代码中怎么操作呢?一行代码就是一个Model。

 public class Backend extends Model {
}

什么都没有啊? 就这么个类,我们看看怎么操作数据库,首先是新建一条记录:

 Map<String, Object> newParams = new HashMap<>();
newParams.put(......)
Backend backend = Backend.create(newParams);
backend.save();

找到并且删除一条记录:

Backend backend = Backend.where(map("name","jack")).fetchOne()
backend.delete()

那没有申明属性,怎么访问属性呢?

String name = backend.attr("name",String.class)

当然,因为我经常会用name属性,我们就申明一下,方便代码提示,不申明可以通过attr去定向拿:

public class Backend extends Model {
private String name;
public String getName() {
return name;
}
}

记住,这里的代码纯粹是为了做代码提示,不是必须的。

你可能会问,ORM里的关联咋办?

public class Backend extends Model {
@OneToMany
private List< Info> infos;
public Association infos(){
throw new AutoGeneration();
}
}

这就是所有,接着你就可以通过类似backend.infos.where(....).fetch()来操作。你不用写任何逻辑代码,ORM会根据你的数据库读取到的元数据自动帮你做关联,自动填充属性,自动提供查询语法(代码提示通过Model类已经写好的方法完成)

Web Contorller,一切只为便捷。

写一个controller 以及一个action,你只要这么做:

 class BackendController extends ApplicationController {
@At(path = Array("/backend/add"), types = Array(GET, POST))
def backendAdd = {
List("url", "tag", "name").foreach(item => require(hasParam(item), s"${item} is required"))
Backend.newOne(params(), true)
BackendService.refreshCache
render(map("msg", "success"))
}
}

继承ApplicationController,就是一个controller,@就定义了请求的endpoint。http参数怎么获取?使用param方法:

val name = param("name")
paramAsInt("times",0) // 获取int类型参数,并且默认值设置为0
hasParam("name")//判断有没有
params() //拿到所有参数

比如前面的例子,我们鼓励直接在controller里使用模型类操作数据库,免去了service的麻烦,因为model已经具有足够的表达能力,很多业务逻辑也可以放在model里。

这不比通过定义方法的参数强很多?定义方法的参数你会说便于测试,我们看SF怎么做接口测试的:

 @Test
public void search() throws Exception {
RestResponse response = get("/doc/blog/search", map(
"tagNames", "_10,_9"
));
Assert.assertTrue(response.status() == 200);
Page page = (Page) response.originContent();
Assert.assertTrue(page.getResult().size() > 0);
}

So Easy.

基于HTTP协议的伪RPC协议

越来越多的人喜欢HTTP协议而非PPC, PRC无论测试还是复杂度其实都大于HTTP,但是每次调用HTTP接口还是很麻烦的,SF提供了一个对HTTP自动包装的接口(动态生成代理类的方式),你只要提供HTTP接口代码,就可以直接使用。比如:

 trait BackendService {
@At(path = Array("/run/script"), types = Array(GET, POST))
def runScript(@Param("sql") sql: String): HttpTransportService.SResponse @At(path = Array("/run/script"), types = Array(GET, POST))
def runScript(params: Map[String, String]): HttpTransportService.SResponse @At(path = Array("/run/sql"), types = Array(GET, POST))
def runSQL(params: Map[String, String]): HttpTransportService.SResponse @At(path = Array("/instance/resource"), types = Array(GET, POST))
def instanceResource(params: Map[String, String]): HttpTransportService.SResponse
}

这个接口是没有任何实现的,他对应的是后端一个服务的http接口。接着我们在SF里就可以这么调用了:

val instance = ClientProxy.get[BackendService]()
instance.runScript(params().asScala.toMap)

是不是很easy,很PRC?

后话

使用SF,你只需要几分钟就能搭建一个可以运行,具备部分业务逻辑功能的API服务。去掉尽量多的层,尽量让使用者可以用最简单的办法去完成对应的功能而不是去考虑一些设计的优雅性来完成一些功能特点。 大家可以查看mlsql-cluster 获得更多使用范例,感受其魅力。

另外,我个人认为比较完美的一个组合是: Reactjs + ServiceFramework

ServiceFramework作为Java Web框架都有哪些不错的设计的更多相关文章

  1. 《架构探险——从零开始写Java Web框架》这书不错,能看懂的入门书

    这书适合我. 哈哈,结合 以前的知识点,勉强能看懂. 讲得细,还可以参照着弄出来. 希望能坚持 完成啦... 原来,JSTL就类似于DJANGO中的模板. 而servlet类中的res,req,玩了D ...

  2. 读《架构探险——从零开始写Java Web框架》

    内容提要 <架构探险--从零开始写Java Web框架>首先从一个简单的 Web 应用开始,让读者学会如何使用 IDEA.Maven.Git 等开发工具搭建 Java Web 应用:接着通 ...

  3. 架构探险笔记3-搭建轻量级Java web框架

    MVC(Model-View-Controller,模型-视图-控制器)是一种常见的设计模式,可以使用这个模式将应用程序进行解耦. 上一章我们使用Servlet来充当MVC模式中的Controller ...

  4. java web框架发展的新趋势--跨界轻型App

    “跨界(cross over)在汽车界已然成风,将轿车.SUV.跑车和MPV等多种不同元素融为一体的混搭跨界车型,正在成为汽车设计领域的新趋势.从个人而言,当包容.多元的审美要求和物质要求越来越强烈时 ...

  5. Java Web框架前景浅析

    基于三(多)层架构模式,典型WEB系统的总体架构如下图所示: 在上述分层架构中,整个应用被划分为两大部分: 客户端:基于浏览器提供信息展现.用户交互等功能.所采用的技术主要有:HTML/HTML5.J ...

  6. JAVA web 框架集合

    “框架”犹如滔滔江水连绵不绝, 知道有它就好,先掌握自己工作和主流的框架: 在研究好用和新框架. 主流框架教程分享在Java帮帮-免费资源网 其他教程需要时间制作,会陆续分享!!! 152款框架,你还 ...

  7. 五大 JAVA Web 框架的优缺点对比,Spring MVC 领先

    毫无疑问,Java 是当今世界上最重要的编程语言之一.js 框架给程序员提供了 一个可以构建程序的坚实基础.它包括定义的类和功能,用于硬件设备管理,与系统软件交互并处理输入,让开发人员变得更轻松.Ja ...

  8. 浅析Java Web框架技术

    一.Java Web框架技术的概念 所谓的Java框架,简单理解是一个可复用的设计构件,它规定了应用的体系结构,阐明了整个设计.协作构件之间的依赖关系.责任分配和控制流程,表现为一组抽象类以及其实例之 ...

  9. [转]轻量级 Java Web 框架架构设计

    工作闲暇之余,我想设计并开发一款轻量级 Java Web 框架,看看能否取代目前最为流行的而又越来越重的 Spring.Hibernate 等框架.请原谅在下的大胆行为与不自量力,本人不是为了重造轮子 ...

随机推荐

  1. 查看服务器tcp连接及服务器并发

    一.查看哪些IP连接本机netstat -an二.查看TCP连接数1)统计80端口连接数netstat -nat|grep -i "80"|wc -l 2)统计httpd协议连接数 ...

  2. MFC文件IO和串行化

    一. MFC中CFile对象实现了磁盘文档的读写,但是大部分MFC应用程序的IO服务都使用CArchive对象来完成.不管CFile和Archive输入输出的都是二进制数据,非文本数据. int a ...

  3. eclipse经常出现——未响应!!!

    现象:启动eclipse缓慢,启动完成经常出现未响应情况.偶然在打开一个项目时候,也出现未响应. 原因:虚拟内存不足,或者电脑本身内存不足.但是目前绝大多数PC而言,内存应该是充足的,因此可以修改虚拟 ...

  4. 在Azure DevOps Server (TFS 2019) 流水线传递参数

    变量概述 在Azure DevOps Server的流水线中,变量是衔接不同任务和不通代理之间的桥梁,它可以使相对松散.各自独立的任务之间相关影响并共享数据.在流水线中使用变量,可以在各任务之间相互调 ...

  5. 从文本中读取字符——feof函数问题

    feof()函数 函数原型:int feof(FILE *fp): 函数功能:检测流上的文件结束符,如果文件结束,则返回非0值,否则返回0,文件结束符只能被clearerr()函数清除 (函数feof ...

  6. 关于 SQL 注入的问题

    拼串 (Statement)方式 1.编译次数多,效率比较低:会出现SQL注入问题(数据安全问题):先传参数再编译. 2.Sql文对应的字符串不一样,需要再次编译.Sql文对应的字符串一样,不会再编译 ...

  7. Android开发工程师文集-1 小时学会SQLite

    前言 大家好,给大家带来Android开发工程师文集-1 小时学会SQLite的概述,希望你们喜欢 内容 什么是Sqlite: 效率高,开源,小型,程序驱动,支持事务操作,无数据类型,可嵌入的关系型数 ...

  8. Swift5 语言指南(十三) 方法

    方法是与特定类型相关联的函数.类,结构和枚举都可以定义实例方法,这些方法封装了用于处理给定类型的实例的特定任务和功能.类,结构和枚举也可以定义类型方法,它们与类型本身相关联.类型方法类似于Object ...

  9. 剑指offer【01】- 二维数组中的查找(Java)

    在经历了春招各大公司的笔试题和面试官的血虐之后,决定要刷一些算法题了,不然连面试机会都没有. 而应对笔试和面试,比较出名的就是剑指offer的题目和LeetCode的题目了.剑指offer应对面试中的 ...

  10. odoo开发笔记 -- 搜索视图继承扩展

    odoo开发笔记 -- 搜索视图继承扩展