一.Spring @Async异步方法
在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的;但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3.x之后,就已经内置了@Async来完美解决这个问题。
-
何为异步调用?
在解释异步调用之前,我们先来看同步调用的定义;同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果。 异步调用则是只是发送了调用的指令,调用者无需等待被调用的方法完全执行完毕;而是继续执行下面的流程。
例如, 在某个调用中,需要顺序调用 A, B, C三个过程方法;如他们都是同步调用,则需要将他们都顺序执行完毕之后,方算作过程执行完毕; 如B为一个异步的调用方法,则在执行完A之后,调用B,并不等待B完成,而是执行开始调用C,待C执行完毕之后,就意味着这个过程执行完毕了。
2. 常规的异步调用处理方式
在Java中,一般在处理类似的场景之时,都是基于创建独立的线程去完成相应的异步调用逻辑,通过主线程和不同的线程之间的执行流程,从而在启动独立的线程之后,主线程继续执行而不会产生停滞等待的情况。
3. @Async介绍
在Spring中,基于@Async标注的方法,称之为异步方法;这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。这里的dubbo是同步接口。
@Service
public class AsyncMyService {
@Reference(version = "1.0.0")
private IDubboDemoService dubboDemoService;
@Async
public Future<String> hello(String name) throws MyException {
AsyncResult<String> result = new AsyncResult<>(dubboDemoService.sayHello(name));
return result;
}
}
- 返回类型
需要注意的异步调用的返回是AsyncResult,而要想获得返回则需要通过future.get()。获取异步方法的结果信息,是通过不停的检查Future的状态来获取当前的异步方法是否执行完毕来实现的。
@Test
public void testAsync() {
Future<String> result = null;
try {
result = asyncMyService.hello("asd");
String str = result.get();
System.out.println("Result from asynchronous process - " + str);
} catch (Exception e) {
e.printStackTrace();
}
}
这样看更加明显一些:
@Test
public void testAsync() {
Future<String> result = null;
try {
result = asyncMyService.hello("asd");
while (true) { ///这里使用了循环判断,等待获取结果信息
if (result.isDone()) { //判断是否执行完毕
System.out.println("Result from asynchronous process - " + result.get());
break;
}
System.out.println("Continue doing something else. ");
Thread.sleep(500);
}
} catch (Exception e) {
e.printStackTrace();
}
}
二、异步dubbo
可能还会有这样一种场景,我们在调用dubbo时,不关心其返回值(有点像mq的使用方式),此时就可以用到dubbo异步方法。Dubbo异步方法基于NIO的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小。
springboot-33-异步方法和dubbo异步调用
-
服务提供方
注解的方法非常简单,在服务提供方配置如下:@Service(version=“1.0.0”, async = true)
@Service(version="1.0.0", async = true)
public class DubboDemoServiceImpl implements IDubboDemoService {
@Resource(name = "producer")
private Producer producer;
@Resource(name = "myTopic")
private ActiveMQTopic myTopic;
@Override
public String sayHello(String name) throws MyException {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(name.equals("Tom")) {
throw new RuntimeException("The Name is Tom! He is not a good man!");
}
producer.send(myTopic, "heheda");
return "hello " + name;
}
@Override
public String sayYourAge(int age) throws MyException{
return null;
}
}
-
服务消费方:@Reference(version = "1.0.0",async = true)
@Service
public class MyService {
@Reference(version = "1.0.0", async = true)
private IDubboDemoService dubboDemoService;
public String hello(String name) throws MyException {
String result = dubboDemoService.sayHello(name);
return result;
}
}
-
完全不理会返回
按照以上两步,可以实现dubbo服务的异步调用,但是会发现在服务端报错:
Caused by: java.nio.channels.ClosedChannelException: null。
要想消除这种错误,注解就无能为力了,必须使用xml,使得dubbo异步方法的返回为false。
此时完全忽略返回值,可以配置return=“false”,以减少Future对象的创建和管理成本:
<dubbo:method name=“findFoo” async=“true” return=“false” />
参考:
http://blog.csdn.net/chenaini119/article/details/51850526
http://dubbo.io/user-guide/demos/异步调用.html
http://www.cnblogs.com/lcngu/p/6185363.html