ZeroC ICE java異步實現方式(ami/amd)


首先說說ami 和amd 的區別(以下為個人見解,僅供參考。如有疑問歡迎提出來)

ami (異步方法調用): 

僅僅基於ice 的同步方式擴展了異步的擴展方式,其他理念改動不大,使用起來好理解,但是服務端依賴異步線程數量配置,線程數量如果爆倉,據文檔描述后面的請求全部都會丟失。

 

amd(異步分派方法):

優化ami關於線程數限制的缺點。(摘自Ice中文教程

在使用 AMD 時,服務器可以接收一個請求,然后掛起其處理,
以盡快釋放分派線程。當處理恢復、結果已得出時,服務器要使用 Ice run
time 提供的回調對象,顯式地發送響應。
用實際的術語說, AMD 操作通常會把請求數據 (也就是,回調對象和
操作參數)放入隊列 ,供應用的某個線程 (或線程池)隨后處理用。這
樣,服務器就使分派線程的使用率降到了最低限度,能夠高效地支持數千
並發客戶。
另外, AMD 還可用於需要在完成了客戶的請求之后繼續進行處理的操
作。為了使客戶的延遲降到最低限度,操作在返回結果后,仍留在分派線
程中,繼續用分派線程執行其他工作。

)。就是說每次服務器吧每次請求都放在線程池中掛起,直至開始處理這個請求。並且在將結果返回個客戶端后還可以接着執行其他工作。比如一些掃尾工作不用在返回客戶端結果前做,可以之后做,明顯可以降低客戶等待時間。

 

開始上代碼:

ami異步方法調用:

1、先定義slice接口

["ami"]interface TestAnys1{//接口內的方法全部都是ami模式
            
        string getAnysString();
    };

 

2、服務端繼承_TestAnys1Disp類,實現處理方法

/**
 * ami服務端實現類
 * @author laobiao
 *
 */
public class TestAnys1I extends _TestAnys1Disp{

    @Override
    public String getAnysString(Current __current) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("的撒旦撒");
        
        return "返回結果字符串";
    }
    
}

 

3、簡單的服務發布

package testIceAnysServer.ami;


public class Server extends Ice.Application {

    public static void main(String[] args) {
        
        //實例化服務
                Server app = new Server();
                //啟動服務(這里執行了run方法)
                int status=app.main("Server", args);
                System.exit(status);
        
    }

    @Override
    public int run(String[] args) {
        Ice.ObjectAdapter adapter = communicator().createObjectAdapterWithEndpoints("AnysAmi", "default -p 8778");
        Ice.Object servant = new TestAnys1I();

        adapter.add(servant, Ice.Util.stringToIdentity("testAmi"));
        adapter.activate();
        communicator().waitForShutdown();
        return 0;
    }

}

到此服務端工作完成

 

4、客戶端實現異步回調方法  AMI_TestAnys1_getAnysString 為ICE自動生成的接口回調抽象類(AMI_slice定義的接口名_接口中的方法名)

package testIceAnysServer.ami;

import Ice.LocalException;
import model.AMI_TestAnys1_getAnysString;
/**
 * Ami客戶端回調
 * @author laobiao
 *
 */
public class TestAnys1_interpolateI extends AMI_TestAnys1_getAnysString{
  /**
  * 無異常返回結果回調 
  */ @Override
public void ice_response(String __ret) { System.out.println("客戶端收到回調信息:"+__ret); }
/**
  * 異常返回結果回調 
  */
@Override public void ice_exception(LocalException ex) { System.out.println("客戶端收到異常:"+ex.getMessage()); } }

 

5、簡單的客戶端請求請求數據方式

package testIceAnysServer.ami;


import model.TestAnys1Prx;
import model.TestAnys1PrxHelper;

public class Client {

    public static void main(String[] args) {
        int status = 0;
        // 定義通信器
        Ice.Communicator ic = null;
        try {
            // Create a communicator
            // 實例化通信器
            ic = Ice.Util.initialize(args);
            // Create a proxy for the root directory
            // 實例化通信代理
            Ice.ObjectPrx base = ic.stringToProxy("testAmi:default -p 8778");
            if (base == null)
                throw new RuntimeException("Cannot create proxy");
            //獲取代理
            TestAnys1Prx TestAnys1I = TestAnys1PrxHelper.checkedCast(base);
            if (TestAnys1I == null)
                throw new RuntimeException("Invalid proxy");
            //定義回調方式
            TestAnys1_interpolateI zz=new TestAnys1_interpolateI();
            //注入回調方式,請求數據
            TestAnys1I.begin_getAnysString(zz);
            
            System.out.println("完成");
        } catch (Ice.LocalException e) {
            e.printStackTrace();
            status = 1;
        } catch (Exception e) {
            System.err.println(e.getMessage());
            status = 1;
        } finally {
            // Clean up
            //
            if (ic != null)
                ic.destroy();
        }
        System.exit(status);

    }

}

至此客戶端完成。

輸出打印結果應該為:

完成
收到回調信息:返回結果字符串
 
        

 

amd異步分派方法:

1、定義slice:

["amd"]interface TestAnys2{//當前接口下所有方法都是amd模式
            
        string getAnysString();
    };

 

2、服務端繼承 _TestAnys2Disp 抽象類,實現接口方法處理

package testIceAnysServer.amd;

import Ice.Current;
import model.AMD_TestAnys2_getAnysString;
import model._TestAnys2Disp;
/**
 * 服務端AMD模式處理方法
 * @author laobiao
 *
 */
public class TestAnys2 extends _TestAnys2Disp{

    @Override
    public void getAnysString_async(AMD_TestAnys2_getAnysString __cb, Current __current) {
        System.out.println("服務端執行方法");
        __cb.ice_response("返回結果字符串");//這里已經將結果返回給客戶端了
        
        System.out.println("開始掃尾工作");
        //..............
        
    }

}

 

3、服務端開啟

package testIceAnysServer.amd;


public class Server extends Ice.Application {

    public static void main(String[] args) {
        
        //實例化服務
                Server app = new Server();
                //啟動服務(這里執行了run方法)
                int status=app.main("Server", args);
                System.exit(status);
        
    }

    @Override
    public int run(String[] args) {
        Ice.ObjectAdapter adapter = communicator().createObjectAdapterWithEndpoints("AnysAmd", "default -p 8778");
        Ice.Object servant = new TestAnys2();

        adapter.add(servant, Ice.Util.stringToIdentity("testAmd"));
        adapter.activate();
        communicator().waitForShutdown();
        return 0;
    }

}

至此服務端代碼完成 可以開啟服務了

 

4、客戶端 繼承抽象類 Callback_TestAnys2_getAnysString (Callback_slice定義的接口名_接口方法) 實現回調處理方法

package testIceAnysServer.amd;

import Ice.LocalException;
import model.AMD_TestAnys2_getAnysString;
import model.Callback_TestAnys2_getAnysString;


/**
 * 客戶端AMD模式回調方法
 * @author laobiao
 *
 */
public class TestAnys2_interpolatel extends Callback_TestAnys2_getAnysString{


  //無異常回調處理方式
    @Override
    public void response(String __ret) {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("收到回調信息:"+__ret);
            
    }
  //發生異常結果回調處理方式
    @Override
    public void exception(LocalException __ex) {
        System.out.println("收到異常:"+__ex.getMessage());            
    }

}

 

5、客戶端啟動並執行方法

package testIceAnysServer.amd;


import Ice.LocalException;
import model.Callback_TestAnys2_getAnysString;
import model.TestAnys1Prx;
import model.TestAnys1PrxHelper;
import model.TestAnys2Prx;
import model.TestAnys2PrxHelper;

public class Client {

    public static void main(String[] args) {
        int status = 0;
        // 定義通信器
        Ice.Communicator ic = null;
        try {
            // Create a communicator
            // 實例化通信器
            ic = Ice.Util.initialize(args);// 實例化通信代理
            Ice.ObjectPrx base = ic.stringToProxy("testAmd:default -p 8778");
            if (base == null)
                throw new RuntimeException("Cannot create proxy");
            
            TestAnys2Prx TestAnys2 = TestAnys2PrxHelper.checkedCast(base);
            if (TestAnys2 == null)
                throw new RuntimeException("Invalid proxy");
            
            TestAnys2.begin_getAnysString(new TestAnys2_interpolatel());
            //System.out.println(s);
            System.out.println("完成");
        } catch (Ice.LocalException e) {
            e.printStackTrace();
            status = 1;
        } catch (Exception e) {
            System.err.println(e.getMessage());
            status = 1;
        } finally {
            // Clean up
            //
            if (ic != null)
                ic.destroy();
        }
        System.exit(status);

    }

}

 

至此客戶端編碼工作完成。

 

執行客戶端輸出應該為:

完成
收到回調信息:返回結果字符串
 
        

 

 

 

思考:

  在上述兩種模式中,我發現使用ice異步的兩種模式流程很相似。都是在服務端實現業務處理方法,在客戶端實現回調方法。但是他們代碼層面來說一種服務端直接實現業務的返回方法(ami  直接renturn結果)。另一種直接使用返回方法而是抓住持有返回方法的對象在需要的時候再返回結果(amd),這就給我們提供能更多的擴展方式。

 

資料參考:Ice_中文教程

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM