摘要:介紹是一個輕量級的服務框架,源代碼位于。是的消息路由器,是具體負責每一個請求的路由過程。當執行結束后,向服務池歸還資源。在多線程模式下,同樣也是在服務線程中執行接口的三種方法。是一個接口,主要代表服務輸出的消息實例。
1.0 Alogic-FrameWork介紹
Alogic-FrameWork是一個輕量級的Java服務框架,源代碼位于Alogic-Github。具有快速開發服務的特點,在alogic-framework下,一個成熟的Java開發者可以快速的開發出實現自己業務邏輯的Restful服務。在這里我們不談具體的開發邏輯,而是專注于分析該框架的源碼。
Alogic-FrameWork的一個HelloWorld級別代碼如下:Alogic的HelloWorld-Github
其中主要包括以下幾個部分:
HelloWorld.java 服務調用的具體內容
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/*的全部路由,其中初始化參數handler為MessageRouterServletHandler類。我們來看一下如何進行這個過程:
1.2 服務上下文的處理ServletAgent是一個代理類,繼承自HttpServlet,主要代理了Servlet的初始化、執行和銷毀,其中重寫了init(ServletConfig servletConfig),它通過ClassLoader類加載器加載實際處理的ServletHandler,并由ServletHandler去執行它的初始化方法。
public void init(ServletConfig servletConfig) throws ServletException { // 獲取handler參數 String handlerClass = servletConfig.getInitParameter("handler"); // 獲取當前Servlet的上下文 ServletContext sc = servletConfig.getServletContext(); // 獲取當前web項目類加載器 ClassLoader classLoader = (ClassLoader) sc.getAttribute("classLoader"); if (classLoader != null) { try { //創建Handler實例 handler = (ServletHandler) classLoader.loadClass(handlerClass) .newInstance(); //執行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中需要配置它的實現方法,MessageRouterServletHandler是它的具體實現類,在init實現方法中,設置了一些關鍵屬性,如Http的編碼、跨域、緩存等屬性,以及獲取服務id、目錄、訪問控制等。
在doService實現方法中,將上述初始化的一些列屬性設置,達到重新封裝Http請求的目的;service方法初始化Context,并將參數作為輸入傳入到action方法中。如下:
// 初始化HttpContext,HttpContext是Context類的一個實現,它是一個封裝后的Http請求的上下文。 HttpContext ctx = new HttpContext(request,response,encoding,interceptMode); // 獲取當前服務路徑的id Path id = normalizer.normalize(ctx, request); MessageRouter.action(id,ctx,ac);1.3 服務請求過程
上文提到過,MessageRouterServletHandler實現了ServletHandler接口,將Http上下文封裝起來,同時將doService方法中獲取得到的服務id,訪問控制給MessageRouter的action方法。MessageRouter是Alogic的消息路由器,是具體負責每一個請求的路由過程。在action方法中,包括以下邏輯:
處理路由追蹤
獲取服務實例池
通過訪問控制器分配訪問優先級
從服務實例池獲取實例
日志記錄
首先,MessageRouter根據獲取得到的服務id來獲取一個服務實例池,通過資源池模式來保證服務實例的不斷重復利用。資源池獲取代碼如下:
// 獲取服務實例池 ServantFactory factory = servantFactory; // 根據服務id獲取服務工廠 pool = factory.getPool(id); if (!pool.isRunning()){ throw new ServantException("core.service_paused", "The Service is paused:service id:" + id); }
而接著,對于已經獲得的資源池中根據優先級獲得服務實例。在非線程模式下調用execute()方法,在多線程模式下建立服務工作線程。當執行結束后,向服務池歸還資源。
//從服務實例池中拿服務實例,并執行 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(); // 判斷服務工作線程是否在指定的時間內建立完成。如果超時則取消主線程阻塞狀態,并 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方法執行了服務調用的前置方法、執行方法和后置方法。
protected static int execute(Servant servant,Context ctx) throws Exception { servant.actionBefore(ctx); servant.actionProcess(ctx); servant.actionAfter(ctx); return 0; }
在多線程模式下,同樣也是在服務線程中執行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等協議的消息實例,如輸出為RawMessage時,finish方法如下:
public void finish(Context ctx,boolean closeStream) { // 設置輸出流 OutputStream out = null; try { // 設置返回內容格式 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); } }
到此,一個服務的執行邏輯如下:
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/67378.html
摘要:而用于主線程池的屬性都定義在中本篇只是簡單介紹了一下引導類的配置屬性,下一篇我將詳細介紹服務端引導類的過程分析。 從Java1.4開始, Java引入了non-blocking IO,簡稱NIO。NIO與傳統socket最大的不同就是引入了Channel和多路復用selector的概念。傳統的socket是基于stream的,它是單向的,有InputStream表示read和Outpu...
摘要:雖然蘋果官方提供了關于的與使用說明,但這并不能滿足開發者們的需求,各類復雜場景依舊讓我們焦頭爛額,而解決方案卻不易尋找。二源碼下載編譯及調試之前我們首先需要獲取一份蘋果官方的源碼。 一、前言移動互聯網時代,網頁依舊是內容展示的重要媒介,這離不開 WebKit 瀏覽內核技術的支持與發展。在 iOS 平臺下開發者們...
閱讀 1858·2021-11-22 15:24
閱讀 1313·2021-11-12 10:36
閱讀 3211·2021-09-28 09:36
閱讀 1843·2021-09-02 15:15
閱讀 2756·2019-08-30 15:54
閱讀 2397·2019-08-30 11:02
閱讀 2397·2019-08-29 13:52
閱讀 3545·2019-08-26 11:53