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_中文教程

 

posted @ 2017-07-24 01:57  搬砖工的奋斗史  阅读(2775)  评论(0编辑  收藏  举报