ServiceFramework作為Java Web框架都有哪些不錯的設計

来源:https://www.cnblogs.com/aishangJava/archive/2018/12/11/10105533.html
-Advertisement-
Play Games

前言 最近需要開發一個純API的項目,mlsql-cluster,從無到有,到最後完整的proxy功能開發完畢,只花了四個小時不到,自己不盡小感嘆了一把 ServiceFramework的高效。 關於ServiceFramework的誕生 ServiceFramework算是一個古老的,基於Java ...


前言

最近需要開發一個純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里的鏈接信息:

   

接著你按傳統的方式在資料庫里建好表,比如

1 CREATE TABLE backend
2 (
3   id                   int(11) NOT NULL AUTO_INCREMENT,
4   name                 varchar(255) DEFAULT NULL,
5   url                  text,
6   tag                  text,
7   ecs_resource_pool_id int(11),
8   PRIMARY KEY (id)
9 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

創建了一張backend表。然後我要在代碼中怎麼操作呢?一行代碼就是一個Model。

1 public class Backend extends Model {
2 }

什麼都沒有啊? 就這麼個類,我們看看怎麼操作資料庫,首先是新建一條記錄:

1 Map<String, Object> newParams = new HashMap<>();
2 newParams.put(......)
3 Backend backend = Backend.create(newParams);
4 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,你只要這麼做:

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

繼承ApplicationController,就是一個controller,@就定義了請求的endpoint。http參數怎麼獲取?使用param方法:

val name = param("name") 
paramAsInt("times",0) // 獲取int類型參數,並且預設值設置為0
hasParam("name")//判斷有沒有
params() //拿到所有參數

比如前面的例子,我們鼓勵直接在controller里使用模型類操作資料庫,免去了service的麻煩,因為model已經具有足夠的表達能力,很多業務邏輯也可以放在model里。

這不比通過定義方法的參數強很多?定義方法的參數你會說便於測試,我們看SF怎麼做介面測試的:

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

So Easy.

基於HTTP協議的偽RPC協議

越來越多的人喜歡HTTP協議而非PPC, PRC無論測試還是複雜度其實都大於HTTP,但是每次調用HTTP介面還是很麻煩的,SF提供了一個對HTTP自動包裝的介面(動態生成代理類的方式),你只要提供HTTP介面代碼,就可以直接使用。比如:

 1 trait BackendService {
 2   @At(path = Array("/run/script"), types = Array(GET, POST))
 3   def runScript(@Param("sql") sql: String): HttpTransportService.SResponse
 4 
 5   @At(path = Array("/run/script"), types = Array(GET, POST))
 6   def runScript(params: Map[String, String]): HttpTransportService.SResponse
 7 
 8   @At(path = Array("/run/sql"), types = Array(GET, POST))
 9   def runSQL(params: Map[String, String]): HttpTransportService.SResponse
10 
11   @At(path = Array("/instance/resource"), types = Array(GET, POST))
12   def instanceResource(params: Map[String, String]): HttpTransportService.SResponse
13 }

這個介面是沒有任何實現的,他對應的是後端一個服務的http介面。接著我們在SF里就可以這麼調用了:

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

是不是很easy,很PRC?

後話

使用SF,你只需要幾分鐘就能搭建一個可以運行,具備部分業務邏輯功能的API服務。去掉儘量多的層,儘量讓使用者可以用最簡單的辦法去完成對應的功能而不是去考慮一些設計的優雅性來完成一些功能特點。 大家可以查看mlsql-cluster 獲得更多使用範例,感受其魅力。

另外,我個人認為比較完美的一個組合是: Reactjs + ServiceFramework

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 平時在開發過程中dao、bean和XML文件都是自動生成的,很少寫XML的配置關係,今天記錄一下mybatis的關聯查詢中的多對一和一對多的情況。 首先是有兩張表(學生表Student和老師Teacher表),為了更易懂,這裡只設置了最簡單的幾個必要欄位。表結構如下圖: Student表: ​ Te ...
  • 0、介紹 本篇文章是在我看完《從零開始學架構》之後,以架構演變為主線,梳理了一下演變過程中出現的問題以及解決方案,文章中引用了這本書的一些內容和圖片 分散式和集群的概念經常被搞混,現在一句話讓你明白兩者的區別。 分散式:一個業務拆分成多個子業務,部署在不同的伺服器上集群:同一個業務,部署在多個伺服器 ...
  • 機房同傳了新的系統,不使用dev的話每次開機都要重新更改環境變數(其實也可以在編譯命令里添加絕對路徑)。所以就去學習了一下用bat腳本更改pat ...
  • 需求分析: 當一個龐大的系統中有很多小模塊,在分配路由的時候怎麼處理呢?全部都堆到一個py程式中,調用@app.route? 顯然這是很不明智的,因為當有幾十個模塊需要寫路由的時候,這樣程式員寫著寫著自己就暈掉了。同時也違背了面向對象設計原則中的控制反轉原則。模塊與模塊之間應該不要太緊密的依賴,高級 ...
  • java基礎之反射 1. 類的載入、連接和初始化 1.1 類的載入 1.2 類的連接 1.3 類的初始化 1.4 類載入器 2. 反射 2.1 反射基本信息 2.1.1 Class對象 2.1.2 Java反射機制的類庫支持 2.2 反射的基本實現 2.2.1 獲取Class對象 2.2.2 獲取構... ...
  • 1、Readme 文件,告訴別人如何使用你的程式(必須) 2、代碼加註釋,讓別人可以輕鬆讀懂你的代碼(必須) 3、目錄結構要符合規範,每天單獨一個目錄,如Day1,Day2,Day3..(必須) 4、流程圖,幫自己理清思路、幫別人更容易瞭解你的代碼設計邏輯(必須) 5、blog(博客),寫好blog ...
  • 在 Laravel 編寫單元測試時經常會遇到需要模擬認證用戶的時候,比如新建文章、創建訂單等,那麼在 Laravel unit test 中如何來實現呢? 官方解決方法 Laravel 的官方文檔中的測試章節中有提到: Of course, one common use of the session ...
  • Berlekamp Massey演算法 很久之前就聽說過這個演算法,當時六校聯考的時候Day1T1是一道很有意思的遞推,神仙zzx不會做於是就拿BM演算法艹出了遞推式Orzzzzzzzzzzx "推薦一篇講的詳細的不能再詳細的博客" 我就不詳細說了,只記一下自己感覺比較難理解的地方 設$r(m)$表示序列 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...