基於RxJava的函式式Reactive Web框架:datamill
datamill是一個基於RxJava開發函式響應式風格的Java Web框架,可看成是SpringBoot競爭的框架,使用Java8和lambda,它不同於其他Java框架,使得透過整個應用的資料流和行為變為高度可見的,這樣你不需要使用魔術效果元註釋,使得很多效果隱藏在複雜的框架和文件後面,相反,你只要顯式明確指定資料是如何在你的應用中流動,如何修改這些資料即可。只需要使用簡單的RxJava風格即可。
當你使用Spring框架時,雖然只需要很少程式碼就可以跑起來,但是當專案複雜以後,你會發現很多功能和行為被使用元註解隱藏在了框架和文件後面,變得難以捉摸和不確定性。但是你如果不想使用元註釋,你會遇到阻礙,你需要除錯數百行框架自身的程式碼以找出背後的原理機制,以及如何搞定框架以讓它做你想做的事情。
看看datamill的簡單程式碼:
datamill應用總是以標準的Java應用開始,可以明確地建立HTTP伺服器,指定請求如何被處理,以及伺服器監聽埠,不像傳統的JEE部署,你得配置servlet容器或應用伺服器的配置,你只要啟動這段伺服器程式碼你就控制了一切,這也使得為這個伺服器建立Docker容器變得很簡單,只要使用Maven打包一個可執行的JAR包即可,放入標準的Java Dcoker容器即可。
當Http到達你的伺服器,它是如何流過你的應用變得顯著可見:
rb.ifMethodAndUriMatch(Method.GET, "/status", r -> r.respond(b -> b.ok()))
這一行程式碼說伺服器首先檢查請求應該是一個從URI為/status的GET請求,如果是,返回HTTP是ok的響應。
下面兩行顯示你能組織你的請求處理器,同時能夠保持對請求之後如何處理也就是發生了什麼情況保持可讀性和可維護性。
.elseIfMatchesBeanMethod(outlineBuilder.wrap(new UserController()))
這段程式碼是說看看請求是否匹配UserController例項的一個處理方法,為了理解這個匹配工作原理,我們看看UserController的類,下面是處理請求的方法程式碼:
你能看到我們使用@Path和@Get元註釋標記為請求處理器方法。這裡你就不需要像Spring框架需要挖掘框架數百行程式碼以搞清楚框架是如何路由你的請求到你的程式碼。
最後,請注意在UserController中響應是如何被建立的,是如何顯式進行JSON組合的:
你能充分控制JSON到內部細節,也不需要使用Jackson進行JSON自定義,或者使用Spring Data REST試圖定製自己的響應,這些煩惱和複雜都沒有了。
下面再看看你一個倉儲查詢程式碼:
注意,這裡精確SQL查詢可自由組合,對於那些使用元註釋產生查詢語句的人來說,你會再次體會到清晰。
在一個簡單應用中,查詢中有很小比例需要超過JPA實現以外進行定製,幾乎所有應用都有這種情況,這時你開始鑽研框架內部程式碼時會變得非常消沉。
請注意這裡資料是如何從查詢結果中取出來放入實體的,最後注意程式碼還能保持怎樣的精確,這些都是使用lambda和RxJava可觀察操作的原因。
當你使用Spring框架時,雖然只需要很少程式碼就可以跑起來,但是當專案複雜以後,你會發現很多功能和行為被使用元註解隱藏在了框架和文件後面,變得難以捉摸和不確定性。但是你如果不想使用元註釋,你會遇到阻礙,你需要除錯數百行框架自身的程式碼以找出背後的原理機制,以及如何搞定框架以讓它做你想做的事情。
看看datamill的簡單程式碼:
public static void main(String[] args) { OutlineBuilder outlineBuilder = new OutlineBuilder(); Server server = new Server( rb -> rb.ifMethodAndUriMatch(Method.GET, "/status", r -> r.respond(b -> b.ok())) .elseIfMatchesBeanMethod(outlineBuilder.wrap(new TokenController())) .elseIfMatchesBeanMethod(outlineBuilder.wrap(new UserController())) .orElse(r -> r.respond(b -> b.notFound())), (request, throwable) -> handleException(throwable)); server.listen(8081); } <p class="indent"> |
datamill應用總是以標準的Java應用開始,可以明確地建立HTTP伺服器,指定請求如何被處理,以及伺服器監聽埠,不像傳統的JEE部署,你得配置servlet容器或應用伺服器的配置,你只要啟動這段伺服器程式碼你就控制了一切,這也使得為這個伺服器建立Docker容器變得很簡單,只要使用Maven打包一個可執行的JAR包即可,放入標準的Java Dcoker容器即可。
當Http到達你的伺服器,它是如何流過你的應用變得顯著可見:
rb.ifMethodAndUriMatch(Method.GET, "/status", r -> r.respond(b -> b.ok()))
這一行程式碼說伺服器首先檢查請求應該是一個從URI為/status的GET請求,如果是,返回HTTP是ok的響應。
下面兩行顯示你能組織你的請求處理器,同時能夠保持對請求之後如何處理也就是發生了什麼情況保持可讀性和可維護性。
.elseIfMatchesBeanMethod(outlineBuilder.wrap(new UserController()))
這段程式碼是說看看請求是否匹配UserController例項的一個處理方法,為了理解這個匹配工作原理,我們看看UserController的類,下面是處理請求的方法程式碼:
@Path("/users") public class UserController { ... @GET @Path("/{userName}") public Observable<Response> getUser(ServerRequest request) { return userRepository.getByUserName(request.uriParameter("userName").asString()) .map(u -> new JsonObject() .put(userOutlineCamelCased.member(m -> m.getId()), u.getId()) .put(userOutlineCamelCased.member(m -> m.getEmail()), u.getEmail()) .put(userOutlineCamelCased.member(m -> m.getUserName()), u.getUserName())) .flatMap(json -> request.respond(b -> b.ok(json.asString()))) .switchIfEmpty(request.respond(b -> b.notFound())); } ... } <p class="indent"> |
你能看到我們使用@Path和@Get元註釋標記為請求處理器方法。這裡你就不需要像Spring框架需要挖掘框架數百行程式碼以搞清楚框架是如何路由你的請求到你的程式碼。
最後,請注意在UserController中響應是如何被建立的,是如何顯式進行JSON組合的:
.map(u -> new JsonObject() .put(userOutlineCamelCased.member(m -> m.getId()), u.getId()) .put(userOutlineCamelCased.member(m -> m.getEmail()), u.getEmail()) .put(userOutlineCamelCased.member(m -> m.getUserName()), u.getUserName())) .flatMap(json -> request.respond(b -> b.ok(json.asString()))) <p class="indent"> |
你能充分控制JSON到內部細節,也不需要使用Jackson進行JSON自定義,或者使用Spring Data REST試圖定製自己的響應,這些煩惱和複雜都沒有了。
下面再看看你一個倉儲查詢程式碼:
public class UserRepository extends Repository<User> { ... public Observable<User> getByUserName(String userName) { return executeQuery( (client, outline) -> client.selectAllIn(outline) .from(outline) .where().eq(outline.member(m -> m.getUserName()), userName) .execute() .map(r -> outline.wrap(new User()) .set(m -> m.getId(), r.column(outline.member(m -> m.getId()))) .set(m -> m.getUserName(), r.column(outline.member(m -> m.getUserName()))) .set(m -> m.getEmail(), r.column(outline.member(m -> m.getEmail()))) .set(m -> m.getPassword(), r.column(outline.member(m -> m.getPassword()))) .unwrap())); } ... } <p class="indent"> |
注意,這裡精確SQL查詢可自由組合,對於那些使用元註釋產生查詢語句的人來說,你會再次體會到清晰。
在一個簡單應用中,查詢中有很小比例需要超過JPA實現以外進行定製,幾乎所有應用都有這種情況,這時你開始鑽研框架內部程式碼時會變得非常消沉。
請注意這裡資料是如何從查詢結果中取出來放入實體的,最後注意程式碼還能保持怎樣的精確,這些都是使用lambda和RxJava可觀察操作的原因。
相關文章
- Fission:基於Kubernetes的Serverless函式框架Server函式框架
- Spring 5 新特性:函式式Web框架Spring函式Web框架
- 基於函式的索引函式索引
- # vue3 ref 和 reactive 函式VueReact函式
- vue3函式setUp和reactive函式詳細講解Vue函式React
- 部署基於pythonwsgiweb框架的工程到函式計算PythonWeb框架函式
- Oracle基於函式的索引Oracle函式索引
- OCP之基於函式的索引函式索引
- 測試建立基於函式的索引函式索引
- Spring基於建構函式和設值函式的依賴注入Spring函式依賴注入
- 全面瞭解Vue3的 reactive 和相關函式VueReact函式
- 基於函式計算的 BFF 架構函式架構
- 基於函式的索引狀態變化函式索引
- RANK函式基於條件的查詢函式
- 基於主函式視角和結構體框架的專案再梳理函式結構體框架
- 《基於MVC的javascript web富應用開發》中的一些函式MVCJavaScriptWeb函式
- Spring Cloud Stream的函式式和響應式Reactive程式設計特點 - spring.ioSpringCloud函式React程式設計
- 函式基礎和函式引數函式
- Oracle 19c中基於函式的索引Oracle函式索引
- 什麼是函式響應式程式設計(Functional Reactive Programming:FRP)函式程式設計FunctionReactFRP
- 函式基礎函式
- [Web框架]Spray基於Scala的REST框架SprayWeb框架REST
- elf,基於flexbox的響應式CSS框架FlexCSS框架
- 基於SPI的增強式外掛框架設計框架
- 關於建構函式與解構函式的分享函式
- gin框架函式語法框架函式
- [Q]怎樣建立基於函式索引zt函式索引
- 基於雜湊函式的簽名,Part-1函式
- 基於函式index的一點簡單測試!函式Index
- query rewrite和基於函式的索引有關係?函式索引
- 基於函式的索引(function-based index,FBI)函式索引FunctionIndex
- 基於Serverless雲函式站點監控的方法Server函式
- RxJava練武場之——基於Observable網路框架的搭建RxJava框架
- 【嵌入式Web伺服器】嵌入式Web框架選型Web伺服器框架
- 關於count函式的理解函式
- 關於lag函式的用法函式
- 介紹基於OpenFaaS函式的knative Build教程 - alexellis函式UI
- 基於NodeJS的14款Web框架NodeJSWeb框架