重要:Missian刚刚更新到0.31,新增了Future风格的回调方式。
Missian没有绑定spring,但是强烈推荐配合spring一起使用。异步客户端由于需要调用BeanLocator去寻找回调的
Bean,如果配合Spring使用,可以直接使用SpringLocator(BeanLocator的唯一实现),否则需要自己实现。
使用异步客户端需要注意一点:由于是异步调用,所以一个远程方法的返回值永远是null(如果不是void的话)或者是原生数据类型的默认值。一段时间后(比如100毫秒)后客户端收到这个返回值,会去找到相应的回调对象进行调用。
异步的优势是:在调用的期间我们不需要像同步调用一样有一个线程一直在等着它的返回值,而是调用完即可返回释放线程,当客户端接受到返回值后会进行
回调,业务流程可以继续往下执行。不要小看这个等待的时间,假如A服务调用了一个跨机房的服务或者一个重型的服务B,那么B的响应时间可能是100毫秒甚
至更多,那么可以想象在高并发的情况下,可能A服务的全部线程都耗死在无穷的等待上了。
我们还是先看看如何配合Spring来使用Missian异步客户端。
步骤一:给Hello.hello(String, int)创建一个回调类
注意和0.2x相比,这里有比较大的不同:
public class HelloCallback {
public void hello(String returnValue) {
System.out.println(returnValue);
}
}
这个类的方法要和Hello接口的方法一一对应,Hello中所有方法(除了返回值为void的方法)都应该有一个回调方法,回调方法名和Hello接口中对应的方法名一样,而且只接受一个参数,参数类型和对应方法的返回值一致。
例如,Hello有一个hello(String, int)方法的返回值是String类型,那么要求HelloCallback必须有一个hello(String)的方法。
步骤二:修改Hello接口,用注解的方法声明回调Bean
这里和0.21前的版本也有所不同,以前这个注解是用在方法上的,现在直接用在接口上,所以一个接口只需要注解一次了。
@CallbackTarget("helloCallback")
public interface Hello {
public String hello(String name, int age);
}
步骤三:在Spring配置文件中配置这个回调Bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- your callback bean, missian client will invoke its execute() method when received the returned object -->
<bean id="helloCallback" class="com.missian.example.bean.HelloCallback">
</bean>
</beans>
步骤四:在Spring中创建AsyncMissianProxyFactory
<bean id="asyncMissianProxyFactory" class="com.missian.client.async.AsyncMissianProxyFactory" init-method="init" destroy-method="destroy">
<constructor-arg >
<bean class="com.missian.common.beanlocate.SpringLocator"/>
</constructor-arg>
</bean>
这里我们使用的是AsyncMissianProxyFactory的最简单的构造函数,只接受一个BeanLocator。这时候默认创建一个4
个线程的线程池用来处理回调逻辑,1个线程用来处理IO,需要指定线程数,或者将一个已经存在的线程池传入,可以参考其它几个构造函数:
public AsyncMissianProxyFactory(BeanLocator callbackLoacator, ExecutorService threadPool, int callbackIoProcesses, boolean logBeforeCodec, boolean logAfterCodec, NetworkConfig networkConfig) {}
public AsyncMissianProxyFactory(BeanLocator callbackLoacator, ExecutorService threadPool, int callbackIoProcesses, boolean logBeforeCodec, boolean logAfterCodec){}
public AsyncMissianProxyFactory(BeanLocator callbackLoacator, ExecutorService threadPool) {}
public AsyncMissianProxyFactory(BeanLocator callbackLoacator, int threadPoolSize, int callbackIoProcesses, boolean logBeforeCodec, boolean logAfterCodec) {}
public AsyncMissianProxyFactory(BeanLocator callbackLoacator, ExecutorService threadPool, NetworkConfig networkConfig) {}
public AsyncMissianProxyFactory(BeanLocator callbackLoacator, int threadPoolSize, int callbackIoProcesses, boolean logBeforeCodec, boolean logAfterCodec, NetworkConfig networkConfig) {}
public AsyncMissianProxyFactory(BeanLocator callbackLoacator, int threadPoolSize){}
假如在服务器里使用Missian客户端,可以考虑将服务器主线程池传入给AsyncMissianProxyFactory,共享线程池。
步骤五:实现异步调用
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/missian/example/client/async/withspring/applicationContext-*.xml");
//actually you can inject AsyncMissianProxyFactory into any other beans to use it.
//we just show how AsyncMissianProxyFactory works here.
AsyncMissianProxyFactory asyncMissianProxyFactory = (AsyncMissianProxyFactory)context.getBean("asyncMissianProxyFactory");
Hello hello = (Hello)asyncMissianProxyFactory.create(Hello.class, "tcp://localhost:1235/hello");
long time = System.currentTimeMillis();
for(int i=0; i<10000; i++) {
hello.hello("gg", 25);
}
System.out.println(System.currentTimeMillis()-time);
}
你可以清楚地看到,所有的请求都发送出去之后,返回值陆续返回并回掉了HelloCallback。
和同步的客户端一样,可以使用http协议发送数据:
Hello hello = (Hello)asyncMissianProxyFactory.create(Hello.class, "http://localhost:1235/hello");
但目前比较遗憾的是,还不能够支持异步调用Hessian服务。
另外需要说明的是,这个直接从Context里面取出AsyncMissianProxyFactory只是用来演示异步调用的用法;正常的做法应该是将AsyncMissianProxyFactory注入到我们需要使用它的Bean。
===============0.31.新增功能分割线===================
如何为重载方法都实现回调?
比如以下两个方法都需要回调:
public interface Hello {
String hello(String name, int age, String country);
String hello(String name, int age);
}
按照上面所说的,他们的回调方法都映射到:
void hello(String);
这样会造成回调错误,因此需要使用一个注解来说明回调方法名:
@CallbackTarget("helloCallback")
public interface Hello {
@CallbackTargetMethod("hello0")
public String hello(String name, int age, String country);
@CallbackTargetMethod("hello1")
public String hello(String name, int age);
}
对应的,回调类的实现:
public class HelloCallback {
public void hello0(String returnValue) {
System.out.println(returnValue);
}
public void hello1(String returnValue) {
System.out.println("hello1:"+returnValue);
}
}
注意如果不使用注解,系统寻找默认的方法。注解同样也可以用于非重载的方法。
另外一种回调的实现
如果不希望使用注解,那么还有另外一种方式可供选择:
如果服务器端的方法是:
String hello(String name, int age);
那么客户端的接口可以写成(注意,Missian不要求服务器端和客户端使用同一个接口类,甚至接口名都可以不同,而只要求方法名及参数必须匹配):
public interface Hello {
public String hello(String name, int age, Callback cb);
}
调用时:
Hello hello = (Hello)factory.create(Hello.class, "http://localhost:1235/hello");
Callback cb = ......
hello.hello("name", 80, cb);
即可以异步调用成功。
Future风格的异步实现
我个人非常喜欢Future这种方法,在Mina中就有大量的使用。同样Missian也提供了这样一个能力。提供了一个AysncFuture,即可以通过get()变成同步,也可以通过addListner()来监听,一旦返回值到达,就会出发监听器。
如果服务器端的方法是:
String hello(String name, int age);
那么客户端的接口可以写成(注意,Missian不要求服务器端和客户端使用同一个接口类,甚至接口名都可以不同,而只要求方法名及参数必须匹配):
public interface Hello {
public AysncFuture<String> hello(String name, int age, Class<String> returnType);
}
调用时:
Hello hello = (Hello)factory.create(Hello.class, "http://localhost:1235/hello");
Async<String> future = hello.hello("name", 80, String.class);
如果想阻塞直到数据返回,那么:
String value = future.get();
System.out.println(value);
如果想通过监听器实现事件驱动:
AsyncListener listener = ....
future.addListener(listener);
分享到:
相关推荐
1. **克隆源码**:使用Git工具克隆"missian-master"仓库到本地。 2. **构建项目**:通过Maven或Gradle等构建工具编译源代码。 3. **阅读文档**:查看项目文档以了解如何配置和服务调用。 4. **编写客户端和服务端**...
6. **Missian ActiveMQ-JMS简单实例**:这可能是一个具体的项目实例,它展示了如何在Spring应用中使用ActiveMQ实现异步RPC(远程过程调用)。在这种模式下,一个服务通过消息将请求发送到队列,另一端的服务监听队列...
基于springboot的招聘求职系统源码数据库文档.zip
基于springboot的校园自助洗衣服务管理系统源码数据库文档.zip
基于java的家乡特产网上商城的开题报告.docx
基于java的校园跑腿管理系统的开题报告
毕业设计&课设_ 健身房管理系统 Java 后端,含多种功能模块,代码完整开源.zip
基于springboot的小学家校互联平台源码数据库文档.zip
基于java的线上选课系统的开题
基于springboot+vue的桂林旅游网站系统源码数据库文档.zip
基于springboot协同过滤算法的个性化音乐推荐系统源码数据库文档.zip
基于SpringBoot的中药材管理系统源码数据库文档.zip
基于springboot的电缆行业生产管理系统源码数据库文档.zip
最新HTML一键打包EXE工具2.0.0, 采用了新的内核, 相比1.x版本, 支持更多最新浏览器特性. HTML一键打包EXE工具能把任意HTML项目(址)一键打包为单个exe文件,在脱离浏览器及服务器的情况下直接运行,支持课件,游戏,址等各类项目.
基于SpringBoot的社区居民诊疗健康管理系统源码数据库文档.zip
上传【mysql数据库项目】资源
压缩文件(3).zip
安装office2010时经常会提示MSXML未安装等问题,导致无法继续安装,使用此一键修复工具可以完美解决
基于springboot的网上商城源码数据库文档.zip
详情介绍 html实现的破碎拼接文字动画特效代码是一段会自动产生文字依次破碎再拼接的效果,非常的炫。欢迎对此段代码感兴趣的朋友前来下载使用。