Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add MotanAsync annotation for async call #372

Merged
merged 3 commits into from
Mar 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 112 additions & 4 deletions docs/wiki/zh_quickstart.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
- [快速入门](#)
- [简单调用示例](#简单调用示例)
- [同步调用](#同步调用)
- [异步调用](#异步调用)
- [集群调用示例](#集群调用示例)
- [使用Consul作为注册中心](#使用Consul作为注册中心)
- [使用ZooKeeper作为注册中心](#使用Zookeeper作为注册中心)
- [使用Consul作为注册中心](#使用consul作为注册中心)
- [使用ZooKeeper作为注册中心](#使用zookeeper作为注册中心)
- [其他调用示例](#其他调用示例)
- [提供YAR协议服务](#提供YAR协议服务)
- [提供YAR协议服务](#提供yar协议服务)
- [使用注解方式配置motan](#使用注解方式配置motan)
- [使用OpenTracing](#使用opentracing)

快速入门中会给出一些基本使用场景下的配置方式,更详细的使用文档请参考[用户指南](zh_userguide).

Expand All @@ -15,6 +18,8 @@

## <a id="peer-to-peer"></a>简单调用示例

### <a id="synccall"></a>同步调用

1. 在pom中添加依赖

```xml
Expand Down Expand Up @@ -144,7 +149,90 @@

执行Client类中的main函数将执行一次远程调用,并输出结果。

### <a id="asynccall"></a>异步调用

异步调用与同步调用基本配置完全一样,只需要在接口类中加上@MotanAsync注解,然后client端稍作修改。server端不需要做任何修改。具体步骤如下:

1. 在接口类上加@MotanAsync注解

```java
package quickstart;

@MotanAsync
public interface FooService {
public String hello(String name);
}
```

2. 编译时,Motan自动生成异步service类,生成路径为target/generated-sources/annotations/,生成的类名为service名加上Async,例如service类名为FooService.java,则自动生成的类名为FooServiceAsync.java。
另外,需要将motan自动生产类文件的路径配置为项目source path,可以使用maven plugin或手动配置。pom.xml配置如下:


```xml
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.10</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/annotations</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
```

3. 在client端配置motan_client.xml时,在同步调用配置的基础上,只需要修改referer的interface为Motan自动生成的接口类即可。

```xml
<motan:referer id="remoteService" interface="quickstart.FooServiceAsync" directUrl="localhost:8002"/>
```

4. 异步使用方式如下:

```java
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] {"classpath:motan_client.xml"});

FooServiceAsync service = (FooServiceAsync) ctx.getBean("remoteService");

// sync call
System.out.println(service.hello("motan"));

// async call
ResponseFuture future = service.helloAsync("motan async ");
System.out.println(future.getValue());

// multi call
ResponseFuture future1 = service.helloAsync("motan async multi-1");
ResponseFuture future2 = service.helloAsync("motan async multi-2");
System.out.println(future1.getValue() + ", " + future2.getValue());

// async with listener
FutureListener listener = new FutureListener() {
@Override
public void operationComplete(Future future) throws Exception {
System.out.println("async call "
+ (future.isSuccess() ? "sucess! value:" + future.getValue() : "fail! exception:"
+ future.getException().getMessage()));
}
};
ResponseFuture future3 = service.helloAsync("motan async multi-1");
ResponseFuture future4 = service.helloAsync("motan async multi-2");
future3.addListener(listener);
future4.addListener(listener);
}
```

具体代码可以参考demo模块

## <a id="cluster"></a>集群调用示例

在集群环境下使用Motan需要依赖外部服务发现组件,目前支持consul或zookeeper。
Expand Down Expand Up @@ -366,7 +454,7 @@ YAR协议使用[yar-java](https://github.com/weibocom/yar-java)进行解析,ja
3、service的实现类上添加@MotanService注解,注解的配置参数与xml配置方式的service标签一致。

```java
@MotanService(export = "8002")
@MotanService(export = "demoMotan:8002")
public class MotanDemoServiceImpl implements MotanDemoService {

public String hello(String name) {
Expand Down Expand Up @@ -449,3 +537,23 @@ server端详细配置请参考motan-demo模块
```

client端详细配置请参考motan-demo模块

## <a id="opentracing"></a>使用OpenTracing

Motan通过filter的SPI扩展机制支持[OpenTracing](http://opentracing.io),可以支持任何实现了OpenTracing标准的trace实现。使用OpenTracing需要以下步骤。

1、引入filter-opentracing扩展

```xml
<dependency>
<groupId>com.weibo</groupId>
<artifactId>motan-protocol-yar</artifactId>
<version>0.2.3</version>
</dependency>
```

2、如果第三方trace工具声明了io.opentracing.Tracer的SPI扩展,直接引入第三方trace的jar包即可。如果第三方没有声明,则转第三步。

3、自定义一个TracerFactory实现TracerFactory接口,通过getTracer()来获取不同tracer实现。设置OpenTracingContext的tracerFactory为自定义的TracerFactory即可。

可参考filter-opentracing模块src/test/java/com.weibo.api.motan.filter.opentracing.zipkin.demo包下的server端和client端实现。
21 changes: 20 additions & 1 deletion motan-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
<name>motan-core</name>

<dependencies>

<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
Expand All @@ -48,5 +47,25 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.squareup</groupId>
<artifactId>javapoet</artifactId>
<version>1.8.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${java.source.jdk}</source>
<target>${java.source.jdk}</target>
<encoding>${project.build.sourceEncoding}</encoding>
<compilerArgument>-proc:none</compilerArgument>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public class MotanConstants {
public static final String DEFAULT_CHARACTER = "utf-8";
public static final int SLOW_COST = 50; // 50ms
public static final int STATISTIC_PEROID = 30; // 30 seconds
public static final String ASYNC_SUFFIX = "Async";// suffix for async call.

/**
* netty channel constants start
**/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import com.weibo.api.motan.rpc.DefaultRequest;
import com.weibo.api.motan.rpc.Referer;
import com.weibo.api.motan.rpc.Response;
import com.weibo.api.motan.rpc.ResponseFuture;
import com.weibo.api.motan.rpc.RpcContext;
import com.weibo.api.motan.switcher.Switcher;
import com.weibo.api.motan.switcher.SwitcherService;
import com.weibo.api.motan.util.ExceptionUtil;
Expand All @@ -52,6 +54,7 @@ public class RefererInvocationHandler<T> implements InvocationHandler {
private List<Cluster<T>> clusters;
private Class<T> clz;
private SwitcherService switcherService = null;
private String interfaceName;

public RefererInvocationHandler(Class<T> clz, Cluster<T> cluster) {
this.clz = clz;
Expand All @@ -73,22 +76,29 @@ private void init() {
String switchName =
this.clusters.get(0).getUrl().getParameter(URLParamType.switcherService.getName(), URLParamType.switcherService.getValue());
switcherService = ExtensionLoader.getExtensionLoader(SwitcherService.class).getExtension(switchName);
interfaceName = MotanFrameworkUtil.removeAsyncSuffix(clz.getName());
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(isLocalMethod(method)){
if("toString".equals(method.getName())){
if (isLocalMethod(method)) {
if ("toString".equals(method.getName())) {
return clustersToString();
}
throw new MotanServiceException("can not invoke local method:" + method.getName());
}
DefaultRequest request = new DefaultRequest();

request.setRequestId(RequestIdGenerator.getRequestId());
request.setArguments(args);
request.setMethodName(method.getName());
String methodName = method.getName();
boolean async = false;
if (methodName.endsWith(MotanConstants.ASYNC_SUFFIX) && method.getReturnType().equals(ResponseFuture.class)) {
methodName = MotanFrameworkUtil.removeAsyncSuffix(methodName);
async = true;
}
RpcContext.getContext().putAttribute(MotanConstants.ASYNC_SUFFIX, async);
request.setMethodName(methodName);
request.setParamtersDesc(ReflectUtil.getMethodParamDesc(method));
request.setInterfaceName(clz.getName());
request.setInterfaceName(interfaceName);
request.setAttachment(URLParamType.requestIdFromClient.getName(), String.valueOf(RequestIdGenerator.getRequestIdFromClient()));

// 当 referer配置多个protocol的时候,比如A,B,C,
Expand All @@ -113,7 +123,11 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
URLParamType.throwException.getValue()));
try {
response = cluster.call(request);
return response.getValue();
if (async && response instanceof ResponseFuture) {
return response;
} else {
return response.getValue();
}
} catch (RuntimeException e) {
if (ExceptionUtil.isBizException(e)) {
Throwable t = e.getCause();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2009-2016 Weibo, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.weibo.api.motan.rpc;

public interface ResponseFuture extends Future, Response{
void onSuccess(Response response);

void onFailure(Response response) ;

long getCreateTime();
}
15 changes: 13 additions & 2 deletions motan-core/src/main/java/com/weibo/api/motan/rpc/URL.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.weibo.api.motan.common.MotanConstants;
import com.weibo.api.motan.common.URLParamType;
import com.weibo.api.motan.exception.MotanServiceException;
import com.weibo.api.motan.util.MotanFrameworkUtil;

/**
* <pre>
Expand Down Expand Up @@ -63,7 +64,7 @@ public URL(String protocol, String host, int port, String path, Map<String, Stri
this.protocol = protocol;
this.host = host;
this.port = port;
this.path = path;
this.path = removeAsyncPath(path);
this.parameters = parameters;
}

Expand Down Expand Up @@ -177,7 +178,7 @@ public String getPath() {
}

public void setPath(String path) {
this.path = path;
this.path = removeAsyncPath(path);
}

public String getVersion() {
Expand Down Expand Up @@ -483,5 +484,15 @@ private Map<String, Number> getNumbers() {
}
return numbers;
}

/**
* because async call in client path with Async suffix,we need
* remove Async suffix in path for subscribe.
* @param path
* @return
*/
private String removeAsyncPath(String path){
return MotanFrameworkUtil.removeAsyncSuffix(path);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2009-2016 Weibo, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.weibo.api.motan.transport.async;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
*
* @Description async request annotation
* @author zhanglei
* @date Feb 21, 2017
*
*/
@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface MotanAsync {

}
Loading