1. 程式人生 > >伺服器端擴充套件 SmartFoxServer 2X

伺服器端擴充套件 SmartFoxServer 2X

伺服器端擴充套件

SmartFoxServer 2X擴充套件在SmartFoxServer Pro的許多方面得到了重新訪問和改進。我們將注意力集中在Java擴充套件開發上,並且已經放棄了對指令碼語言的支援。主要原因是:

效能:用Java編寫的擴充套件程式比任何指令碼語言(如Javascript或Python)都要好一些數量級。隨著面向企業級應用程式的新型伺服器架構,動態語言的使用將很快成為瓶頸。我們仍然認為,剝皮是快速原型創意的好方法,但我們不建議用於生產。為此,您仍然可以插入動態語言引擎(如Rhino和Jython)。
併發性:Java允許完全控制併發,這是伺服器端程式碼的關鍵方面。特別是最新的Java 5/6併發集合和實用程式為開發人員提供了不能從動態語言完全訪問的優秀併發工具。
整合:如果在Java中直接完成,與其他庫的整合更為自然,並避免後續可能在開發中出現的意外後果。

Java擴充套件框架已經大大改進。伺服器端API是為符合最新的Java 6標準而編寫的,它們利用了所有最新的功能,如併發集合,泛型,列舉,註釋等。API還符合Java最佳實踐,提供了前所未有的定製。

簡化了開發週期,以便從IDE中進行一鍵式部署,並且幕後完全管理諸如類路徑修改或類載入事務等複雜操作。
一個擴充套件來統治一切

擴充套件架構中的第一個值得注意的變化是開發人員可以將單個擴充套件外掛插入其房間或區域。這與SmartFoxServer Pro相反,可以附加多個擴充套件。這樣做的理由是,新的擴充套件將允許您以更少的方式做更多的事情:

由於Zone代表在SmartFoxServer中執行的隔離應用程式,因此我們發現使用單擴充套件應用程式模型是提供可擴充套件性的最合乎邏輯的方法。
擴充套件必須被視為包含伺服器應用程式所有邏輯的Java程式。使用簡單的物件OOP實踐,您可以像編寫獨立應用程式一樣分開程式碼的關注。新的Extensions API還將通過一套新的工具來幫助您完成此項工作。
使用單個擴充套件允許將狀態儲存在中心位置,並與程式碼中的所有類共享。
使用單個擴充套件消除了尷尬的互操作性工具的需要,這些工具只會使程式碼的流程複雜化,並增加了類載入和併發問題。

»擴充套件概述

Java擴充套件部署在單個.jar檔案中,該資料夾代表副檔名。下圖顯示了所有擴充套件程式釋出的根目錄的主副檔名/資料夾。我們的testExtension資料夾包含一個包含我們所有程式碼的jar檔案。
這裡寫圖片描述
還有一些事情要注意:

您可以在同一擴充套件資料夾下部署多個jar檔案,例如依賴關係或其他庫。它們都將被載入到相同的類載入器下。
有一個名為__lib__的專用資料夾,您可以在其中放置依賴關係。這樣,您可以選擇哪些庫在多個擴充套件中共享,哪些庫在特定擴充套件中是本地的。

這兩種方法都可以有用,取決於您需要做什麼:

在Extension資料夾下部署的庫將被載入到Extension Class Loader中。這意味著您可以更改該特定庫而不影響其他擴充套件。
在__lib__資料夾下共享的庫將載入到父類載入器中。如果您更改任何這些依賴關係,它將影響使用它們的所有擴充套件。

»定製配置

每個擴充套件可以自動載入包含您的程式碼中可立即可用的自定義設定的.properties檔案。預設情況下,Extension API將嘗試載入一個名為config.properties的檔案,但您可以指定任何其他檔名。當將相同的擴充套件程式附加到多個區域或房間時,這是特別有用的,但是您需要將不同的設定傳遞給每個區域。

這是關於如何在AdminTool中配置擴充套件的示例(請參閱“區域配置器”模組文件中的“區域擴充套件”選項卡或“房間擴充套件”選項卡以獲取其他資訊和重要說明):
這裡寫圖片描述
Where:

名稱是指副檔名,由資料夾名稱表示;
型別表示正在使用的擴充套件的型別(建議使用Java);
主類是主要擴充套件類(或Python指令碼檔名)的完全限定名稱;
使用命名約定不是擴充套件設定:它僅啟用/禁用主類欄位上的過濾器,以僅顯示名稱以“副檔名”結尾的類;
屬性檔案是擴充套件資料夾中部署的.properties檔案的可選名稱,包含自定義擴充套件設定(預設為config.properties);
重新載入模式指示擴充套件是否被監視並自動重新載入(AUTO),手動重新載入(MANUAL)或不可重新載入(NONE)。

»類路徑管理

好訊息是,您不必像SmartFoxServer Pro那樣觸控類路徑。 SmartFoxServer 2X掃描依賴關係和擴充套件資料夾並載入所有的jar檔案。
»副檔名重新載入

SmartFoxServer 2X提供擴充套件熱重新部署,這在開發階段非常有用。當此功能開啟(參見上面的自定義配置段落)時,伺服器將監視您的副檔名資料夾,並在修改jar檔案時重新載入程式碼。
所有您需要做的是配置您的Java IDE直接在SmartFoxServer路徑的Extension資料夾下構建或複製jar檔案,您將擁有一鍵式部署系統。
»必需的依賴項

為了開始建立自己的擴充套件,您需要在最喜歡的IDE中為專案新增一些庫:

lib / sfs2x.jar
lib / sfs2x-core.jar

日誌記錄工具不是強制性的,除非您需要特定的日誌功能:

lib / log4j-1.2.15.jar
lib / slf4j-api-1.5.10.jar
lib / slf4j-log4j12.jar

»伺服器端javadoc

您可以檢視伺服器端API javadoc。 API的主要入口點是com.smartfoxserver.v2.api.SFSApi類。請注意,使用未記錄的方法和屬性可能會導致系統故障。
»看看Extension API

有兩個主要類別為您將建立的任何擴充套件提供基礎:

BaseSFSExtension。提供SmartFoxServer Pro Extensions開發中已知的基本四種方法:init,destroy,handleClientRequest,handleServerEvent。我們已經包括這個課程,主要是為了相容以前的擴充套件方法,但我們認為你會發現下一個更方便。

SFSExtension。這是您應該在Extension主類中繼承的推薦的新基類。 SFSExtension提供了內建的服務,以便適當地分離請求和事件處理程式,在擴充套件和銷燬這些擴充套件時釋放自動偵聽器。

»最簡單的擴充套件可能

我們來看看我們可以寫的最簡單的擴充套件類:

public class MyFirstExtension extends SFSExtension
{
    @Override
    public void init()
    {
        trace("Hello, this is my first SFS2X Extension!");
    }
}

這是建立完全功能擴充套件的最低限度:一種方法init。
當然,你可能已經在想,你將無法用單一的方法完成很多工作,所以讓我們新增一個請求處理程式。 我們希望使用者能夠向我們傳送兩個號碼,我們將新增它們併發送回來。 我們的YouTube頻道也提供了一個完整的視訊教程,介紹如何建立這個簡單的擴充套件程式。

開發擴充套件程式時的推薦做法是,每個請求或事件處理程式都是一個單獨的類,以便清楚地分離程式碼中的每一條邏輯。 我們提供了兩個介面來建立請求處理程式或伺服器事件處理程式。 在我們建立我們的新增請求處理程式之前,我們必須定義我們期望從客戶端得到的引數:在這個簡單的例子中,我們預期會有兩個稱為n1和n2的整數,我們將返回一個二進位制數的整數。

現在我們可以開始編寫處理程式:

public class AddReqHandler extends BaseClientRequestHandler
{
    @Override
    public void handleClientRequest(User sender, ISFSObject params)
    {
        // Get the client parameters獲取客戶端引數
        int n1 = params.getInt("n1");
        int n2 = params.getInt("n2");

        // Create a response object建立響應物件
        ISFSObject resObj = SFSObject.newInstance(); 
        resObj.putInt("res", n1 + n2);

        // Send it back發回它
        send("add", resObj, sender);
    }
}

handleClientRequest方法接收以下兩個引數:

sender:表示傳送請求的客戶端的User物件;
引數:具有使用者傳送的所有引數的物件。 SFSObject是所有物件的肉和馬鈴薯在客戶端和伺服器之間交換。伺服器和客戶端API都提供相同的ISFSObject介面,以確保編碼一致性(閱讀本文件以獲取更多資訊)。

上述示例中的程式碼應該是不言自明的。我們首先獲得兩個預期的整數,為響應準備一個新的SFSObject,並新增結果n1 + n2。最後,我們在父擴充套件上呼叫send方法將響應發回給使用者。以下引數傳遞給方法:

“add”:用於此請求的唯一命令名稱(建議在同一請求/響應對中使用相同的名稱);
resObj:包含傳送到客戶端的資料的SFSObject;
發件人:在此使用表示傳送請求的客戶端的使用者物件,因為我們要將響應傳送回請求者。

為了“連線”這個處理程式與主擴充套件,我們需要做的是在擴充套件的init方法中新增一行:

@Override
public void init()
{
    trace("Hello, this is my first SFS2X Extension!");

    // Add a new Request Handler新增一個新的請求處理程式
    addRequestHandler("add", AddReqHandler.class)
}   

addRequestHandler方法允許註冊特定請求ID的處理程式。 類似地,可以使用addEventHandler方法新增任意數量的伺服器事件處理程式。 這是一個如何監聽USER_LOGIN伺服器事件的示例:

public class LoginEventHandler extends BaseServerEventHandler
{
    @Override
    public void handleServerEvent(ISFSEvent event) throws SFSException
    {
        String name = (String) event.getParameter(SFSEventParam.LOGIN_NAME);

        if (name.equals("Gonzo") || name.equals("Kermit"))
            throw new SFSLoginException("Gonzo and Kermit are not allowed in this Zone!");
    }
}

就像以前一樣,現在我們現在回到主要的擴充套件類修改init方法:

@Override
public void init()
{
    trace("Hello, this is my first SFS2X Extension!");

    // Add a new Request Handler新增一個新的請求處理程式
    addRequestHandler("add", AddReqHandler.class)

    // Add a new SFSEvent Handler新增一個新的SFS事件處理程式
    addEventHandler(SFSEventType.USER_LOGIN, LoginEventHandler.class);
}   

現在我們已經建立了第一個基本的擴充套件,我們可以注意到幾件事情:

 與SFS Pro方法不同,我們不用無限長的if或switch塊將主要的擴充套件程式碼混淆,將請求或事件分派到適當的處理程式;
 在SFS2X擴充套件類中,我們訂閱事件,而不是老系統,其中所有事件始終被觸發到擴充套件,即使他們不需要它們;
 即使它的破壞方法似乎缺少,實際上它不是:它存在於父SFSExtension類中,並不是強制覆蓋它; 如果沒有,則預設行為是呼叫該方法時,所有RequestHandler和EventHandler都將被釋放。

如果您需要自定義destroy方法行為,您可以簡單地覆蓋它。 當然別忘了呼叫super.destroy來確保事件/請求處理程式是自動登出的。

@Override
public void destroy()
{
    super.destroy()

    /*
    * More code here...
    */
}   

總之,還值得一提的是一些有用的方法,它們由任何命令或伺服器處理程式繼承:

getParentExtensions:返回對擴充套件的主類的引用;
getApi:返回對主伺服器端API物件的引用;
傳送:向客戶端傳送分機訊息/響應;
trace:具有各種簽名的有用的日誌記錄方法(有關更多資訊,請參閱javadoc)。

»高階擴充套件功能

現在我們已經介紹了新的Extesion 2.0架構的基礎知識,我們可以深入研究更高階的功能,從而更好地控制程式碼。
»例項化註釋

我們提供了幾個有用的註釋,可以用來指定你的處理程式類應該如何例項化。預設情況下,當您宣告一個請求/事件處理程式類時,這將在每次呼叫時被例項化為新的。您可以使用類上的@Instantiation註釋更改此行為:

@Instantiation(NEW_INSTANCE):在每次呼叫時建立一個新的例項
@Instantiation(SINGLE_INSTANCE):對所有呼叫使用相同的例項

»多處理程式和請求點語法

為了在複雜應用程式中正確組織請求名稱,我們已經建立了類似於使用“點語法”的Java包命名的約定。假設您的擴充套件可以處理一些遊戲和其他操作,如使用者註冊和配置檔案編輯。您可以組織所有這些請求,如下所示:

register.submitForm
register.passwordLost
register.changeEmail
暫存器. ...

profile.changeAvatarType
profile.changeNick
profile.getAvatar
個人資料. ...

checkers.sendMove
checkers.getMyScore
checkers.leave遊戲
跳棋. ...

Extension API提供了一個可以新增到您的處理程式類定義中的@MultiHandler註釋。這將以從某個字首開始的所有請求註冊該類。讓我們為一組請求實現一個多處理程式:

@MultiHandler
public class RegisterMultiHandler extends BaseClientRequestHandler
{
    @Override
    public void handleClientRequest(User sender, ISFSObject params)
    {
        // Obtain the request custom name 獲取請求自定義名稱
        String command = params.getUtfString(SFSExtension.MULTIHANDLER_REQUEST_ID);

        if (command.equals("submitForm"))
            handleSubmitForm(sender, params);
        else if (command.equals("changeEmail"))
            handleChangeEmail(sender, params);

        // ... etc ... 等等
    }

    private void handleSubmitForm(User sender, ISFSObject params)
    {
        // ... app logic here  app邏輯在這裡
    }

    private void handleChangeEmail(User sender, ISFSObject params)
    {
        // ... app logic here
    }
}

在多處理程式中,上述示例中的“暫存器”中的具體請求ID是從傳遞給處理程式的引數物件獲得的。 然後可以使用if或switch語句來根據請求id執行適當的程式碼。

現在我們在之前學到的擴充套件的init方法中註冊該類。

@Override
public void init()
{
    trace("Hello, this is my first multi handler test!");

    // Add a new Request Handler新增一個新的請求處理程式
    addRequestHandler("register", RegisterMultiHandler.class)
}   

在這個例子中唯一真正的區別是處理程式類被標記為@MultiHandler。完成此操作後,擴充套件排程程式將以“register”字首開頭的任何請求ID呼叫處理程式。換句話說,它將處理暫存器。

注意
您還可以將@Instantiation註釋與@MultiHandler註釋混合使用。

總而言之,值得注意的是,您不限於請求名稱中的單個“點”。您可以有多個巢狀級別,例如:games.spacewars.fireBullet或user.profile.avatar.getHairColor等。我們唯一的建議是保持這些請求名稱相當短,因為它們將與請求/響應物件一起傳輸。
»擴充套件濾鏡

此遊覽的最後一個高階功能是擴充套件程式過濾器。如果您熟悉Java Servlet API,這可能會響鈴。 SmartFoxServer中的擴充套件過濾器受到servlet過濾器的啟發,它們具有類似的用途:它們在鏈中執行,它們可以用於在到達擴充套件本身之前記錄,過濾或處理特定請求或事件。

可插拔過濾器的優點是它們不會妨礙您的擴充套件程式碼,它們的執行順序可以被更改,甚至可以在必要時停止執行流程。一個例子可能是一個自定義禁用過濾器,在將請求傳遞給您的登入處理程式之前,使用者憑據將針對黑名單進行檢查。

這是一個簡單的擴充套件過濾器的例子:

public class CustomFilter extends SFSExtensionFilter
{
    @Override
    public void init(SFSExtension ext)
    {
        super.init(ext);
        trace("Filter inited!");
    }

    @Override
    public void destroy()
    {
        trace("Filter destroyed!");
    }

    @Override
    public FilterAction handleClientRequest(String cmd, User sender, ISFSObject params)
    {
        // If something goes wrong you can stop the execution chain here!如果出現問題,可以在這裡停止執行鏈
        if (cmd.equals("BadRequest"))
            return FilterAction.HALT;
        else
            return FilterAction.CONTINUE;
    }

    @Override
    public FilterAction handleServerEvent(ISFSEvent event)
    {
        return FilterAction.CONTINUE;
    }
}

過濾器可以在配置時或動態地在執行時輕鬆新增到任何擴充套件中:

@Override
public void init()
{
    /*
    * This is your Extension main class init()
    */

    // Add filters
    addFilter("customLoginFilter", new CustomLoginFilter());
    addFilter("pubMessageFilter", new PubMessageFilter());
    addFilter("privMessageFilter", new PrivMessageFilter());
}

當新的請求或事件傳送到您的擴充套件時,它將首先按照新增過濾器的順序遍歷過濾器鏈。 在上面的示例中,它將是:customLoginFilter»pubMessageFilter»privMessageFilter»Extension。