摘要:介紹是一個輕量級的服務框架,源代碼位于。是的消息路由器,是具體負責每一個請求的路由過程。當執(zhí)行結束后,向服務池歸還資源。在多線程模式下,同樣也是在服務線程中執(zhí)行接口的三種方法。是一個接口,主要代表服務輸出的消息實例。
1.0 Alogic-FrameWork介紹
Alogic-FrameWork是一個輕量級的Java服務框架,源代碼位于Alogic-Github。具有快速開發(fā)服務的特點,在alogic-framework下,一個成熟的Java開發(fā)者可以快速的開發(fā)出實現(xiàn)自己業(yè)務邏輯的Restful服務。在這里我們不談具體的開發(fā)邏輯,而是專注于分析該框架的源碼。
Alogic-FrameWork的一個HelloWorld級別代碼如下:Alogic的HelloWorld-Github
其中主要包括以下幾個部分:
HelloWorld.java 服務調用的具體內(nèi)容
web.xml web項目構建的配置文件
settings.xml Alogic服務目錄配置文件
servant.xml 服務描述配置文件
1.1 服務初始化入口服務由servlet進行攔截,servlet-class對請求進行處理,并返回響應。
在一個HelloWorld級別的應用中,一個典型的web.xml配置如下:
MessageRouter MessageRouter com.anysoft.webloader.ServletAgent handler com.logicbus.backend.server.http.MessageRouterServletHandler 1 MessageRouter /services/*
服務通過注冊ServletAgent類攔截/services/*的全部路由,其中初始化參數(shù)handler為MessageRouterServletHandler類。我們來看一下如何進行這個過程:
1.2 服務上下文的處理ServletAgent是一個代理類,繼承自HttpServlet,主要代理了Servlet的初始化、執(zhí)行和銷毀,其中重寫了init(ServletConfig servletConfig),它通過ClassLoader類加載器加載實際處理的ServletHandler,并由ServletHandler去執(zhí)行它的初始化方法。
public void init(ServletConfig servletConfig) throws ServletException { // 獲取handler參數(shù) String handlerClass = servletConfig.getInitParameter("handler"); // 獲取當前Servlet的上下文 ServletContext sc = servletConfig.getServletContext(); // 獲取當前web項目類加載器 ClassLoader classLoader = (ClassLoader) sc.getAttribute("classLoader"); if (classLoader != null) { try { //創(chuàng)建Handler實例 handler = (ServletHandler) classLoader.loadClass(handlerClass) .newInstance(); //執(zhí)行Handler的初始化方法 handler.init(servletConfig); } catch (Exception e) { logger.error("Error occurs when creating handler:" + handlerClass, e); } } else { logger.error("Can not find classLoader"); } }
ServletHandler是一個接口,重新封裝了關于Servlet的init、service、destory方法;在web.xml中需要配置它的實現(xiàn)方法,MessageRouterServletHandler是它的具體實現(xiàn)類,在init實現(xiàn)方法中,設置了一些關鍵屬性,如Http的編碼、跨域、緩存等屬性,以及獲取服務id、目錄、訪問控制等。
在doService實現(xiàn)方法中,將上述初始化的一些列屬性設置,達到重新封裝Http請求的目的;service方法初始化Context,并將參數(shù)作為輸入傳入到action方法中。如下:
// 初始化HttpContext,HttpContext是Context類的一個實現(xiàn),它是一個封裝后的Http請求的上下文。 HttpContext ctx = new HttpContext(request,response,encoding,interceptMode); // 獲取當前服務路徑的id Path id = normalizer.normalize(ctx, request); MessageRouter.action(id,ctx,ac);1.3 服務請求過程
上文提到過,MessageRouterServletHandler實現(xiàn)了ServletHandler接口,將Http上下文封裝起來,同時將doService方法中獲取得到的服務id,訪問控制給MessageRouter的action方法。MessageRouter是Alogic的消息路由器,是具體負責每一個請求的路由過程。在action方法中,包括以下邏輯:
處理路由追蹤
獲取服務實例池
通過訪問控制器分配訪問優(yōu)先級
從服務實例池獲取實例
日志記錄
首先,MessageRouter根據(jù)獲取得到的服務id來獲取一個服務實例池,通過資源池模式來保證服務實例的不斷重復利用。資源池獲取代碼如下:
// 獲取服務實例池 ServantFactory factory = servantFactory; // 根據(jù)服務id獲取服務工廠 pool = factory.getPool(id); if (!pool.isRunning()){ throw new ServantException("core.service_paused", "The Service is paused:service id:" + id); }
而接著,對于已經(jīng)獲得的資源池中根據(jù)優(yōu)先級獲得服務實例。在非線程模式下調用execute()方法,在多線程模式下建立服務工作線程。當執(zhí)行結束后,向服務池歸還資源。
//從服務實例池中拿服務實例,并執(zhí)行 servant = pool.borrowObject(priority); // 判斷是否獲取到了服務并輸出錯誤日志 if (servant == null){ logger.warn("Can not get a servant from pool in the limited time,check servant.queueTimeout variable."); ctx.setReturn("core.time_out", "Can not get a servant from pool in the limited time,check servant.queueTimeout variable."); }else{ if (!threadMode){ //在非線程模式下,不支持服務超時 execute(servant,ctx); }else{ // 構建CountDownLatch,用于等待服務工作線程建立。 CountDownLatch latch = new CountDownLatch(1); //建立服務工作線程 ServantWorkerThread thread = new ServantWorkerThread(servant,ctx,latch,tc != null ? tc.newChild() : null); thread.start(); // 判斷服務工作線程是否在指定的時間內(nèi)建立完成。如果超時則取消主線程阻塞狀態(tài),并 if (!latch.await(servant.getTimeOutValue(), TimeUnit.MILLISECONDS)){ ctx.setReturn("core.time_out","Time out or interrupted."); } thread = null; } } }catch (ServantException ex){ ctx.setReturn(ex.getCode(), ex.getMessage()); logger.error(ex.getCode() + ":" + ex.getMessage()); }catch (Exception ex){ ctx.setReturn("core.fatalerror",ex.getMessage()); logger.error("core.fatalerror:" + ex.getMessage(),ex); }catch (Throwable t){ ctx.setReturn("core.fatalerror",t.getMessage()); logger.error("core.fatalerror:" + t.getMessage(),t); } finally { ctx.setEndTime(System.currentTimeMillis()); if (ctx != null){ // 完成Context ctx.finish(); } if (pool != null){ if (servant != null){ // 向服務池歸還資源 pool.returnObject(servant); } // 服務池訪問一次 pool.visited(ctx.getDuration(),ctx.getReturnCode()); if (ac != null){ ac.accessEnd(sessionId,id, pool.getDescription(), ctx); } } if (bizLogger != null){ //需要記錄日志 log(id,sessionId,pool == null ? null : pool.getDescription(),ctx); } if (tracerEnable){ boolean ok = ctx.getReturnCode().equals("core.ok"); Tool.end(tc, "ALOGIC", id.getPath(), ok ?"OK":"FAILED", ok ? ctx.getQueryString() : ctx.getReason(), ctx.getContentLength()); } }
在非線程模式下的execute方法執(zhí)行了服務調用的前置方法、執(zhí)行方法和后置方法。
protected static int execute(Servant servant,Context ctx) throws Exception { servant.actionBefore(ctx); servant.actionProcess(ctx); servant.actionAfter(ctx); return 0; }
在多線程模式下,同樣也是在服務線程中執(zhí)行Servant接口的三種方法。
public void run(){ TraceContext tc = null; if (traceCtx != null){ tc = Tool.start(traceCtx.sn(), traceCtx.order()); } boolean error = false; try { m_servant.actionBefore(m_ctx); m_servant.actionProcess(m_ctx); m_servant.actionAfter(m_ctx); } }1.4 服務響應
在MessageRouter的acion方法中,服務調用的最后會調用ctx.finish(),在這個方法中調用了msg的finish方法。
try { if (!isIgnore()){ if (msg == null){ if (getReturnCode().equals("core.ok")){ response.sendError(404, "No message is found,check servant implemention."); }else{ response.sendError(404, getReturnCode() + ":" + getReason()); } }else{ response.setCharacterEncoding(encoding); msg.finish(this,!cometMode()); } } }
Message是一個接口,主要代表服務輸出的消息實例。在Alogic中,Message可以有XML、JSON等協(xié)議的消息實例,如輸出為RawMessage時,finish方法如下:
public void finish(Context ctx,boolean closeStream) { // 設置輸出流 OutputStream out = null; try { // 設置返回內(nèi)容格式 ctx.setResponseContentType(contentType); out = ctx.getOutputStream(); byte [] bytes = buf.toString().getBytes(ctx.getEncoding()); contentLength += bytes.length; // 將字符串寫到輸出流中 Context.writeToOutpuStream(out, bytes); // 輸出打印 out.flush(); }catch (Exception ex){ logger.error("Error when writing data to outputstream",ex); }finally{ if (closeStream) IOTools.close(out); } }
到此,一個服務的執(zhí)行邏輯如下:
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://www.ezyhdfw.cn/yun/67378.html
摘要:引言給迷失在如何學習區(qū)塊鏈技術的同學一個指引,區(qū)塊鏈技術是隨比特幣誕生,因此要搞明白區(qū)塊鏈技術,應該先了解下比特幣。但區(qū)塊鏈技術不單應用于比特幣,還有非常多的現(xiàn)實應用場景,想做區(qū)塊鏈應用開發(fā),可進一步閱讀以太坊系列。 本文始發(fā)于深入淺出區(qū)塊鏈社區(qū), 原文:區(qū)塊鏈技術學習指引 原文已更新,請讀者前往原文閱讀 本章的文章越來越多,本文是一個索引帖,方便找到自己感興趣的文章,你也可以使用左側...
摘要:而用于主線程池的屬性都定義在中本篇只是簡單介紹了一下引導類的配置屬性,下一篇我將詳細介紹服務端引導類的過程分析。 從Java1.4開始, Java引入了non-blocking IO,簡稱NIO。NIO與傳統(tǒng)socket最大的不同就是引入了Channel和多路復用selector的概念。傳統(tǒng)的socket是基于stream的,它是單向的,有InputStream表示read和Outpu...
摘要:雖然蘋果官方提供了關于的與使用說明,但這并不能滿足開發(fā)者們的需求,各類復雜場景依舊讓我們焦頭爛額,而解決方案卻不易尋找。二源碼下載編譯及調試之前我們首先需要獲取一份蘋果官方的源碼。 一、前言移動互聯(lián)網(wǎng)時代,網(wǎng)頁依舊是內(nèi)容展示的重要媒介,這離不開 WebKit 瀏覽內(nèi)核技術的支持與發(fā)展。在 iOS 平臺下開發(fā)者們...
閱讀 1919·2021-11-22 15:24
閱讀 1361·2021-11-12 10:36
閱讀 3281·2021-09-28 09:36
閱讀 1918·2021-09-02 15:15
閱讀 2818·2019-08-30 15:54
閱讀 2440·2019-08-30 11:02
閱讀 2458·2019-08-29 13:52
閱讀 3595·2019-08-26 11:53