1. 程式人生 > >深入解析Apache Mina原始碼(1)——Mina的過濾器機制實現

深入解析Apache Mina原始碼(1)——Mina的過濾器機制實現

一、責任鏈模式的本來面目

Mina 中有一個重要的設計模式-責任鏈模式,它將此模式成功的應用在了它的過濾器鏈(IoFilterChain)中。開發過J2EE的童鞋們應該對這個模式比較清楚,在Servlet中我們就可以加入Filter的實現,還有Hibernate中也實現了FilterChain。學習怎麼實現責任鏈模式對於我們對開源軟體的學習和以後的工作都會有莫大的幫助。

我們知道計算機系統就是接收資訊,進行資訊處理,資訊輸出的過程,那麼在這個過程中我們加入過濾器有很多好處,訊息經過特定功能的多個過濾器進行逐步處理得到所需要的最終資訊,讓處理過程透明,責任明晰,方便擴充套件。

責任鏈模式的定義我也就不說了,網上一大堆,我的理解是可以把它理解成一個有向連結串列,訊息在這個連結串列中的某個過濾器進行處理然後再傳向下個過濾器,在每個過濾器中都可以處理這些訊息,也可以不處理。如圖:


責任鏈模式的類圖如下:


其實這裡面最核心的就是Handler了,它可是是一個介面或者是一個抽象類,它有對自己的一個引用successor,然後有個處理方法HandleRequest()。因為有了對自己的引用successor所以當本物件不能處理的時候可以轉向successor.HandleRequest()方法,這樣一個“鏈”就形成了。

你應該挺羨慕富士.康裡面生產蘋果手機的工人吧,你平時最喜歡的蘋果手機就是他們生產出來的,他們一個人就能把蘋果手機生產出來嗎?不是的,他們是流水線做業的,OK,流水線就可以看做是責任鏈模式的體現,工人就是鏈條上的一員,有的工人組裝螢幕,有的工人檢查手機,有的工人進行手機的包裝等,下面我們就以程式碼的方式實現:

蘋果手機類:

package com.lifanghu.chain;

/**
 * @author lifh
 * @mail [email protected]
 * @since 2012-6-12 下午11:20:18
 * @name com.lifanghu.chain.Iphone.java
 * @version 1.0
 */

public class Iphone {

    private String state = "我是一臺蘋果機器;";

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

}
 

抽象處理介面類:

package com.lifanghu.chain;



/**
 * @author  lifh
 * @mail    [email protected]
 * @since   2012-6-12 下午11:23:36
 * @name    com.lifanghu.chain.IWorker.java
 * @version 1.0
 */

public interface IWorker {

    /**
     * 處理方法
     * @param iphone
     * @author lifh
     */
    void handleIphone(Iphone iphone);
    /**
     * 設定下一個處理者
     * @param worker
     * @author lifh
     */
    void setNext(IWorker worker);
}
 

具體處理者:

package com.lifanghu.chain;

/**
 * @author lifh
 * @mail [email protected]
 * @since 2012-6-12 下午11:29:46
 * @name com.lifanghu.chain.Worker1.java
 * @version 1.0
 */

public class Worker1 implements IWorker {

    private IWorker next;

    public void handleIphone(Iphone iphone) {
        iphone.setState(iphone.getState() + "我被裝了一個黑色的後蓋;");
        if (next != null)
            next.handleIphone(iphone);
    }

    public void setNext(IWorker worker) {
        this.next = worker;

    }

}
package com.lifanghu.chain;

/**
 * @author lifh
 * @mail [email protected]
 * @since 2012-6-12 下午11:34:32
 * @name com.lifanghu.chain.Worker2.java
 * @version 1.0
 */

public class Worker2 implements IWorker {

    private IWorker next;

    public void handleIphone(Iphone iphone) {
        iphone.setState(iphone.getState() + "我被裝了一塊電池;");
        if (next != null)
            next.handleIphone(iphone);
    }

    public void setNext(IWorker worker) {
        this.next = worker;
    }
}
package com.lifanghu.chain;

/**
 * @author lifh
 * @mail [email protected]
 * @since 2012-6-12 下午11:34:32
 * @name com.lifanghu.chain.Worker3.java
 * @version 1.0
 */

public class Worker3 implements IWorker {

    private IWorker next;

    public void handleIphone(Iphone iphone) {
        iphone.setState(iphone.getState() + "我現在是一臺完整的Iphone了。");
        if (next != null)
            next.handleIphone(iphone);
    }

    public void setNext(IWorker worker) {
        this.next = worker;
    }
}
 

客戶端呼叫者:

package com.lifanghu.chain;

/**
 * @author lifh
 * @mail [email protected]
 * @since 2012-6-12 下午11:37:27
 * @name com.lifanghu.chain.Client.java
 * @version 1.0
 */

public class Client {

    public static void main(String[] args) {
        IWorker worker1 = new Worker1();
        IWorker worker2 = new Worker2();
        IWorker worker3 = new Worker3();

        worker1.setNext(worker2);
        worker2.setNext(worker3);
        Iphone iphone = new Iphone();
        worker1.handleIphone(iphone);

        System.out.println(iphone.getState());
    }
}
 

輸出結果:

 寫道 我是一臺蘋果機器;我被裝了一個黑色的後蓋;我被裝了一塊電池;我現在是一臺完整的Iphone了。  

好了,現在一臺蘋果就組裝完成了,發現了沒有,我們的程式碼比較整潔清新,沒有大量的if/else語句,責任清晰明瞭,呼叫簡單,想要擴充套件的話只需要再實現IWorker介面即可,這就是使用責任鏈模式的好處。

二、Mina是怎麼實現責任鏈模式的

上面介紹了純淨的責任鏈模式,但是在真實的專案中寫程式碼不可能完全照搬,所以多看看開源專案的程式碼寫作方式也許才能真正提高我們的程式設計能力。就以Mina的過濾器鏈來看,對這種模式進行了自己的實現,但是道理是相通的,帶著責任鏈模式的理解去看看Mina的實現是怎樣的。

先看一下Mina過濾器的類圖結構:


從圖中我們可以看出Mina對於此模式的實現是相對比較複雜的,其實從它的程式碼上也可以看出來,當時也是花了好大力氣才把它這塊看明白,其實主要在於理清思路,抓住核心類,最主要的一個介面IoFilterChain和它的一個內部介面Entry,其中IoFilterChain代表了過濾器的容器,它本身就是一個物件引用形成的連結串列結構,預設的實現DefaultIoFilterChain其實有對連結串列頭(head)的引用,找到頭後就可以順著頭向下找,一直找到尾(tail),Entry是對IoFilterNextFilter的封裝整合介面,它屬於連結串列IoFilterChain中的元素。指向當前和下一個過濾器。


EntryImpl 類中包含兩個介面,filternextFilter,他們所用的介面是不一樣的,至於為什麼不用同一個介面,我想可能是因為介面職責單一的原則吧。


 

雖然有IoFilterNextFilter兩個介面,介面方法都差不多,但最後真正業務的執行者還是IoFilter的實現,IoFilterAdapter做為它的預設實現,完成了介面卡的功能,以後的類可以直接繼承它而不用實現IoFilter介面,想實現哪個方法只需要覆蓋IoFilterAdapter的類的方法即可。NextFilter只起到轉發的作用,如訊息接收處理方法(messageReceived):

NextFilter的實現:

//訊息接收到以後NextFilter的實現會把訊息傳遞給nextEntry去處理。
public void messageReceived(IoSession session, Object message) {
    Entry nextEntry = EntryImpl.this.nextEntry;
    callNextMessageReceived(nextEntry, session, message);
}
 

DefaultIoFilterChain再將訊息傳遞給本FiltermessageReceived方法進行實際的訊息接收處理工作:

private void callNextMessageReceived(Entry entry, IoSession session,
        Object message) {
    try {
        IoFilter filter = entry.getFilter();
        NextFilter nextFilter = entry.getNextFilter();
        //本過濾器進行資料處理,完成後再把訊息傳向下個過濾器
        filter.messageReceived(nextFilter, session,
                message);
    } catch (Throwable e) {
        fireExceptionCaught(e);
    }
}
 

當訊息處理完成以後,訊息就要進入到業務處理IoHandler的實現類中去完成業務的相關操作了。這可以在鏈尾看到相關業務傳遞:

@Override
public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
    AbstractIoSession s = (AbstractIoSession) session;
    if (!(message instanceof IoBuffer)) {
        s.increaseReadMessages(System.currentTimeMillis());
    } else if (!((IoBuffer) message).hasRemaining()) {
        s.increaseReadMessages(System.currentTimeMillis());
    }

    try {
        // 最後一個filter會進入到handler進行訊息處理。
        session.getHandler().messageReceived(s, message);
    } finally {
        if (s.getConfig().isUseReadOperation()) {
            s.offerReadFuture(message);
        }
    }
}
 

至此,Mina的連結串列結構就基本講完了,其實仔細看看它的程式碼還是比較容易理解的,可能裡面有些細節還需要我們去琢磨。

連結串列建立了以後,外界是怎樣呼叫的呢?

org.apache.mina.core.filterchain包下我們可以看到類IoFilterEvent,可以看到它實現了基於事件的處理模型,當一個事件(比如接收到訊息)發生後會觸發相應的事件,進而呼叫過濾器鏈的訊息處理功能進行訊息的處理和轉發,這塊其實會有執行緒池的參與完成,會在以後的文章中說明這塊。

public void fire() {
    IoSession session = getSession();
    NextFilter nextFilter = getNextFilter();
    IoEventType type = getType();

    if (DEBUG) {
        LOGGER.debug( "Firing a {} event for session {}",type, session.getId() );
    }

    switch (type) {
    case MESSAGE_RECEIVED:
        //觸發訊息接收
        Object parameter = getParameter();
        nextFilter.messageReceived(session, parameter);
        break;
 

當然也可以直接呼叫:

//觸發過濾器的接收訊息處理
session.getFilterChain().fireMessageReceived(newBuf);

 還有一個類DefaultIoFilterChainBuilder,它以使用者更易用的角度完成了對過濾器鏈的封裝操作,這裡就不細講了。

總結:本文章主要講了責任鏈模式在Mina中的實現,做為一個優秀的框架我們沒理由不好好去學習。

每天進步一點點,不做無為的碼農。。。。。

2012613日星期三

碼農虎虎

[email protected]

相關推薦

深入解析Apache Mina原始碼(1)——Mina過濾器機制實現

一、責任鏈模式的本來面目 Mina 中有一個重要的設計模式-責任鏈模式,它將此模式成功的應用在了它的過濾器鏈(IoFilterChain)中。開發過J2EE的童鞋們應該對這個模式比較清楚,在Servlet中我們就可以加入Filter的實現,還有Hibernate中也實現

深入解析Java反射(1) - 基礎

java blog OS HR gpo n-1 get pos body http://www.sczyh30.com/posts/Java/java-reflection-1/ http://how2j.cn/k/reflection/reflection-usa

深入解析Underscore.js原始碼架構

Underscore.js是很有名的一個工具庫,我也經常用他來處理物件,陣列等,本文會深入解析Underscore原始碼架構,跟大家一起學習下他原始碼的亮點,然後模仿他寫一個簡單的架子來加深理解。他的原始碼通讀下來,我覺得他的亮點主要有如下幾點: * 不需要new的建構函式 * 同時支援靜態方法呼叫和例項方

java基礎(八) 深入解析常量池與裝拆箱機制

java引言 ??本文將介紹常量池 與 裝箱拆箱機制,之所以將兩者合在一起介紹,是因為網上不少文章在談到常量池時,將包裝類的緩存機制,java常量池,不加區別地混在一起討論,更有甚者完全將這兩者視為一個整體,給初學者帶來不少困擾,我就是過來的。同時,也因為包裝類的緩存 與 字符串常量池的思想是一樣的,很容易混

深入解析TensorFlow中滑動平均模型與程式碼實現

因為本人是自學深度學習的,有什麼說的不對的地方望大神指出 指數加權平均演算法的原理 TensorFlow中的滑動平均模型使用的是滑動平均(Moving Average)演算法,又稱為指數加權移動平均演算法(exponenentially weighted

JVM原始碼分析之Attach機制實現完全解讀

Attach是什麼 在講這個之前,我們先來點大家都知道的東西,當我們感覺執行緒一直卡在某個地方,想知道卡在哪裡,首先想到的是進行執行緒dump,而常用的命令是jstack ,我們就可以看到如下執行緒棧了 2014-06-18 12:56:14 Full thread dump Java HotSpot(

深入理解Apache Mina (4)---- IoFilter和IoHandler的區別和聯絡

IoProcessor是一個處理執行緒,它的主要作用是根據當前連線的狀態的變化(建立會話、開啟會話、接收資料、傳送資料、發生異常等等),來將資料或事件通知到IoFilter,當IoFilter的相應的方法接收到該狀態的變化資訊是會對接收到的資料進行處理,處理完畢後會將該事件轉發到IoHandler中,有IoH

MINA原始碼分析---ExecutorFilter執行緒池過濾器

原始碼中都加註釋啦 /* */ package org.apache.mina.filter.executor; import java.util.EnumSet; import java.util.concurrent.Executor; import java.ut

Mina文件 05-過濾器

IoFilter是MINA核心構造之一,起著非常重要的作用。它過濾IoService和IoHandler之間的所有I / O事件和請求。如果您有Web應用程式程式設計經驗,可以放心地認為它是Servlet過濾器的表兄弟。提供了許多開箱即用的過濾器,通過使用開箱即用的過濾器簡化典型的橫切關注點來加速網路應用程式

Mina文檔 05-過濾器

exce string iter 有效 ofb 壓縮 lte let enc IoFilter是MINA核心構造之一,起著非常重要的作用。它過濾IoService和IoHandler之間的所有I / O事件和請求。如果您有Web應用程序編程經驗,可以放心地認為它是Servl

CVPR論文《100+ Times FasterWeighted Median Filter (WMF)》的實現解析(附原始碼)。 任意半徑中值濾波(擴充套件至百分比濾波器)O(1)時間複雜度演算法的原理、實現及效果 任意半徑中值濾波(擴充套件至百分比濾波器)O(1)時間複雜度演算法的原理、實現

  四年前第一次看到《100+ Times FasterWeighted Median Filter (WMF)》一文時,因為他附帶了原始碼,而且還是CVPR論文,因此,當時也對程式碼進行了一定的整理和解讀,但是當時覺得這個演算法雖然對原始速度有不少的提高,但是還是比較慢。因此,沒有怎麼在意,這幾天有幾位朋友

Mina Core 12-日誌過濾器

背景 Apache MINA使用一個系統,允許基於MINA的應用程式的開發人員使用他們自己的日誌記錄系統。       SLF4J MINA採用Simple Logging Facade for Java(SLF4J)。您可以在此處找到有關SLF4J的資

最新Vue.js 原始碼全方位深入解析分享

第1章 準備工作介紹了 Flow、Vue.js 的原始碼目錄設計、Vue.js 的原始碼構建方式,以及從入口開始分析了 Vue.js 的初始化過程。1-1 課程簡介1-2 準備工作1-3 認識 Flow-文件1-4 認識 Flow1-5 Vue.js 原始碼目錄設計-文件1-6 Vue.js

LRU演算法,以及Apache LRUMap原始碼解析

1. 什麼是LRU LRU(least recently used) : 最近最少使用 LRU就是一種經典的演算法,在容器中,對元素定義一個最後使用時間,當新的元素寫入的時候,如果容器已滿,則淘汰最近最少使用的元素,把新的元素寫入。 1.1 自定義實現LRU的要求 比

ItemDecoration深入解析與實戰(一)——原始碼分析

一 概述 ItemDecoration 是 RecyclerView 中的一個抽象靜態內部類。 An ItemDecoration allows the application to add a special drawing and layout offset to specific item v

Vue.js 原始碼全方位深入解析(完整版)

. 第1章 準備工作介紹了 Flow、Vue.js 的原始碼目錄設計、Vue.js 的原始碼構建方式,以及從入口開始分析了 Vue.js 的初始化過程。1-1 課程簡介1-2 準備工作1-3 認識 Flow-文件1-4 認識 Flow1-5 Vue.js 原始碼目錄設計-文

Vue.js 原始碼全方位深入解析(已完結)

第1章 準備工作介紹了 Flow、Vue.js 的原始碼目錄設計、Vue.js 的原始碼構建方式,以及從入口開始分析了 Vue.js 的初始化過程。1-1 課程簡介1-2 準備工作1-3 認識 Flow-文件1-4 認識 Flow1-5 Vue.js 原始碼目錄設計-文件

Android 8.1 原始碼_核心篇 -- 深入研究 PackageManagerService 系列(1

開篇 前言 如果你真正的深入分析過 PackageManagerService,你會發現 PackageManagerService 的原始碼真的很大,而且邏輯、結構都甚為複雜。對 PackageManagerService 系列的原始碼分析是基於 Android

《Hadoop技術內幕:深入解析Hadoop和HDFS》2.1配置檔案簡介

2.1 配置檔案簡介 配置檔案是一個靈活系統不可缺少的一部分,雖然配置檔案非常重要,但卻沒有標準。 本節我們來了解 Windows 作業系統和 Java 環境中的配置檔案。 2.1.1 Windows 作業系統的配置檔案 Windows 系統廣泛使用一種特殊化的 AS

深入理解Feign之原始碼解析

什麼是Feign Feign是受到Retrofit,JAXRS-2.0和WebSocket的影響,它是一個jav的到http客戶端繫結的開源專案。 Feign的主要目標是將Java Http 客戶端變得簡單。Feign的原始碼地址:https://github.com/Op