我們已經知道,iohandler是開發網絡應用程式的時候,與實際業務邏輯相關的元件,即屬于mina核心架構之外的應用層元件。從mina 官方文檔上,我們幾乎沒有看到對ioprocessor的說明,實際上ioprocessor對實際使用mina架構的開發人員透明,無需你去了解它的實作邏輯,它在mina中用來處理實際的i/o操作。
我們分析的思路是,先分别對iohandler與ioprocessor進行單獨分析,然後再闡述它們之間的不同以及聯系。
iohandler
當我們通過iosession執行相關操作的時候,如寫資料,這些事件會觸發mina架構抽象的ioservice執行個體,進而調用mina架構底層的相關元件進行處理。這時,配置的iohandler就被用來處理mina所觸發的相關事件,處理這些事件的操作被抽象出來。
實際上,iohandler的繼承層次非常簡單,也說明了基于mina架構開發實際網絡應用程式,對業務邏輯的處理也還是相對比較容易的。看一下 iohandler的繼承層次,如圖所示:

iohandler接口所定義的操作,一共定義了7個處理事件的操作,如下所示:
<code>1</code>
<code>public</code> <code>interface</code> <code>iohandler {</code>
<code>2</code>
<code></code><code>void</code> <code>sessioncreated(iosession session)</code><code>throws</code> <code>exception;</code>
<code>3</code>
<code></code><code>void</code> <code>sessionclosed(iosession session)</code><code>throws</code> <code>exception;</code>
<code>4</code>
<code></code><code>void</code> <code>sessionidle(iosession session, idlestatus status)</code><code>throws</code> <code>exception;</code>
<code>5</code>
<code></code><code>void</code> <code>exceptioncaught(iosession session, throwable cause)</code><code>throws</code> <code>exception;</code>
<code>6</code>
<code></code><code>void</code> <code>messagereceived(iosession session, object message)</code><code>throws</code> <code>exception;</code>
<code>7</code>
<code></code><code>void</code> <code>messagesent(iosession session, object message)</code><code>throws</code> <code>exception;</code>
<code>8</code>
<code>}</code>
因為iohandler是一個接口,是以如果使用該接口我們就必須實作所有的方法,mina通過使用iohandleradapter來預設實作 iohandler接口,并在iohandleradapter中全部給出空實作,如果我們要開發自己的iohandler,可以繼承自iohandleradapter,根據需要選擇重寫指定的處理mina事件的方法,而對于你不感興趣的方法就預設不給予實作(預設使用 iohandleradapter的空實作)。
那麼,mina調用iohandler的時機是什麼呢?又是如何調用的呢?
其實,根據mina的架構,我們知道,在用戶端主動發起i/o操作請求以後,會等待mina觸發相應的事件,在經過一組iofilter之後,在 iofilter鍊的最後一個iofilter被調用将要結束的時候,會調用我們注冊的iohandler實作,經過處理來滿足實際業務邏輯需要。我們可以在defaultiofilterchain中看到一個内部iofilter實作類tailfilter,在該類裡調用了 iohandler封裝的邏輯,代碼如下所示:
<code>01</code>
<code>private</code> <code>static</code> <code>class</code> <code>tailfilter</code><code>extends</code> <code>iofilteradapter {</code>
<code>02</code>
<code></code><code>@override</code>
<code>03</code>
<code></code><code>public</code> <code>void</code> <code>sessioncreated(nextfilter nextfilter, iosession session)</code><code>throws</code><code>exception {</code>
<code>04</code>
<code></code><code>try</code> <code>{</code>
<code>05</code>
<code></code><code>session.gethandler().sessioncreated(session);</code>
<code>06</code>
<code></code><code>}</code><code>finally</code> <code>{</code>
<code>07</code>
<code></code><code>// notify the related future.</code>
<code>08</code>
<code></code><code>connectfuture future = (connectfuture) session.removeattribute(session_created_future);</code>
<code>09</code>
<code></code><code>if</code> <code>(future !=</code><code>null</code><code>) {</code>
<code>10</code>
<code></code><code>future.setsession(session);</code>
<code>11</code>
<code></code><code>}</code>
<code>12</code>
<code>13</code>
<code>14</code>
<code>15</code>
<code>16</code>
<code></code><code>public</code> <code>void</code> <code>sessionopened(nextfilter nextfilter, iosession session)</code><code>throws</code><code>exception {</code>
<code>17</code>
<code></code><code>session.gethandler().sessionopened(session);</code>
<code>18</code>
<code>19</code>
<code>20</code>
<code>21</code>
<code></code><code>public</code> <code>void</code> <code>sessionclosed(nextfilter nextfilter, iosession session)</code><code>throws</code><code>exception {</code>
<code>22</code>
<code></code><code>abstractiosession s = (abstractiosession) session;</code>
<code>23</code>
<code>24</code>
<code></code><code>s.gethandler().sessionclosed(session);</code>
<code>25</code>
<code>26</code>
<code>27</code>
<code></code><code>s.getwriterequestqueue().dispose(session);</code>
<code>28</code>
<code>29</code>
<code>30</code>
<code></code><code>s.getattributemap().dispose(session);</code>
<code>31</code>
<code>32</code>
<code>33</code>
<code></code><code>// remove all filters.</code>
<code>34</code>
<code></code><code>session.getfilterchain().clear();</code>
<code>35</code>
<code>36</code>
<code></code><code>if</code> <code>(s.getconfig().isusereadoperation()) {</code>
<code>37</code>
<code></code><code>s.offerclosedreadfuture();</code>
<code>38</code>
<code>39</code>
<code>40</code>
<code>41</code>
<code>42</code>
<code>43</code>
<code>44</code>
<code>45</code>
<code>46</code>
<code></code><code>public</code> <code>void</code> <code>sessionidle(nextfilter nextfilter, iosession session, idlestatus status)</code><code>throws</code> <code>exception {</code>
<code>47</code>
<code></code><code>session.gethandler().sessionidle(session, status);</code>
<code>48</code>
<code>49</code>
<code>50</code>
<code>51</code>
<code></code><code>public</code> <code>void</code> <code>exceptioncaught(nextfilter nextfilter, iosession session, throwable cause)</code><code>throws</code> <code>exception {</code>
<code>52</code>
<code>53</code>
<code>54</code>
<code></code><code>s.gethandler().exceptioncaught(s, cause);</code>
<code>55</code>
<code>56</code>
<code>57</code>
<code></code><code>s.offerfailedreadfuture(cause);</code>
<code>58</code>
<code>59</code>
<code>60</code>
<code>61</code>
<code>62</code>
<code>63</code>
<code></code><code>public</code> <code>void</code> <code>messagereceived(nextfilter nextfilter, iosession session, object message)</code><code>throws</code> <code>exception {</code>
<code>64</code>
<code>65</code>
<code></code><code>if</code> <code>(!(message</code><code>instanceof</code> <code>iobuffer)) {</code>
<code>66</code>
<code></code><code>s.increasereadmessages(system.currenttimemillis());</code>
<code>67</code>
<code></code><code>}</code><code>else</code> <code>if</code> <code>(!((iobuffer) message).hasremaining()) {</code>
<code>68</code>
<code>69</code>
<code>70</code>
<code>71</code>
<code>72</code>
<code></code><code>session.gethandler().messagereceived(s, message);</code>
<code>73</code>
<code>74</code>
<code>75</code>
<code></code><code>s.offerreadfuture(message);</code>
<code>76</code>
<code>77</code>
<code>78</code>
<code>79</code>
<code>80</code>
<code>81</code>
<code></code><code>public</code> <code>void</code> <code>messagesent(nextfilter nextfilter, iosession session, writerequest writerequest)</code><code>throws</code> <code>exception {</code>
<code>82</code>
<code></code><code>session.gethandler().messagesent(session, writerequest.getmessage());</code>
<code>83</code>
<code>84</code>
<code>85</code>
<code>86</code>
<code></code><code>public</code> <code>void</code> <code>filterwrite(nextfilter nextfilter, iosession session, writerequest writerequest)</code><code>throws</code> <code>exception {</code>
<code>87</code>
<code></code><code>nextfilter.filterwrite(session, writerequest);</code>
<code>88</code>
<code>89</code>
<code>90</code>
<code>91</code>
<code></code><code>public</code> <code>void</code> <code>filterclose(nextfilter nextfilter, iosession session)</code><code>throws</code> <code>exception {</code>
<code>92</code>
<code></code><code>nextfilter.filterclose(session);</code>
<code>93</code>
<code>94</code>
在上面的代碼中,正好調用了iohandler接口定義的7個處理事件的方法。如果你還想知道iofilterchain執行個體是在何時被調用的, 可以跟蹤mina的源碼。
* ioprocessor
基于網絡的端到端的通信,mina通過一個iosession對象(任何擷取到一個iosession執行個體的持有者都可以)來間接執行 i/o操作,如發送資料、讀取資料等。在mina内部,當一個iosession調用對應的方法,則直接觸發ioprocessor來對指定的事件進行處理,它基于ractor模式來簡化網絡傳輸的實作(事實上,java nio就是基于reactor模式實作,屬于同步非阻塞io模式)。
我們看一下ioprocessor相關類的繼承關系,如圖所示:
看到上面abstractpollingconnectionlessioacceptor,我們知道,它同時也是ioservice的實作,用于網絡通信中的服務端,處理接收請求。可見,對于基于udp/ip的傳輸,ioacceptor和ioprocessor的處理是實作在一起的,可能實際處理的邏輯本身比較簡單,放到一起能夠更好地表達它們之間的緊密聯系。
下面我們看一下ioprocessor接口的定義,如下所示:
<code>public</code> <code>interface</code> <code>ioprocessor<s</code><code>extends</code> <code>iosession> {</code>
<code></code><code>boolean</code> <code>isdisposing();</code>
<code></code><code>boolean</code> <code>isdisposed();</code>
<code></code><code>void</code> <code>dispose();</code>
<code></code><code>void</code> <code>add(s session);</code>
<code></code><code>void</code> <code>flush(s session);</code>
<code></code><code>void</code> <code>write(s session, writerequest writerequest);</code>
<code></code><code>void</code> <code>updatetrafficcontrol(s session);</code>
<code></code><code>void</code> <code>remove(s session);</code>
我們根據上面接口總結一下,一個ioprocessor實際處理了如下内容:
添加iosession執行個體,主要是使用ioprocessor内部的一個iosession隊列newsessions來存放。
flush指定iosession執行個體到ioprocessor内部的flushingsessions隊列。
write一個iosession執行個體對應的writerequest,主要是将一個writerequest加入到 iosession執行個體所持有的writerequestqueue writerequestqueue隊列。至于加入到隊列的請求何時處理,其實我們可以參考ioprocessor的實作abstractpollingioprocessor 類,其内部有一個org.apache.mina.core.polling.abstractpollingioprocessor.processor 線程類,這個線程會在調用一個ioprocessor的方法public final void add(s session)的時候被啟動(實際,在調用dispose()、add(s session)、remove(s session)這三個方法的時候,都會嘗試着去啟動一個processor線程,如果沒有啟動則會啟動這個線程),然後反複循環檢測并處理隊列中的寫請求。
當ioprocessor關閉與一個iosession執行個體執行個體相關的連接配接,則會将這個iosession執行個體從 removingsessions隊列中移除。
控制處理事件的通信量,主要是控制讀寫:如果沒有注冊讀操作(selectionkey.op_read),則注冊一個,否則當一個 讀操作已經就緒,則進行讀資料的處理;如果沒有注冊寫操作(selectionkey.op_write),則注冊一個,否則當一個寫操 作已經就緒,則進行寫資料的處理。
釋放所有與ioprocessor有關的資源。
總結
經過上面的對比,我們已經能夠知道iohandler與ioprocessor的本質差別。
iohandler是在iofilterchain執行中最後一個iofilter中被調用,比如,經過iofilterchain進行 codec、logging等等操作之後,已經将通信層的資料轉化成我們需要的業務對象資料,這時就可以調用我們定義的iohandler實 現來進行處理。
ioprocessor是與實際的socket或channel相關的操作緊密相關的,也就是說,它是支撐mina進行處理底層實際i/o請 求的處理器。