文章14 | 阅读 6822 | 点赞0
本文将会给大家介绍一下在Dubbo中如何开发rest风格的服务接口,然后也会通过一个小demo做个演示案例。
在之前的版本中如果想用Dubbo提供rest风格的接口,可以使用当当网的Dubbox,GitHub地址为:https://github.com/dangdangdotcom/dubbox, 不过在2015年更新到2.8.4版本之后已经停止更新,不过好消息是Dubbo官方在2.6.0版本已经合并了Dubbox的部分功能,目前已经支持提供rest风格的服务了。
以下摘自维基百科:
个人感觉好处主要有以下几点(欢迎补充):
Dubbo基于标准的Java REST API——JAX-RS 2.0(Java API for RESTful Web Services的简写)实现的REST调用支持。
JAX-RS是JAVA EE6 引入的一个新技术。 JAX-RS即Java API for RESTful Web Services,是一个Java 编程语言的应用程序接口,支持按照表述性状态转移(REST)架构风格创建Web服务。JAX-RS使用了Java SE5引入的Java注解来简化Web服务的客户端和服务端的开发和部署。
JAX-RS得到了业界的广泛支持和应用,其著名的开源实现就有很多,包括Oracle的Jersey,RedHat的RestEasy,Apache的CXF和Wink,以及restlet等等。另外,所有支持JavaEE 6.0以上规范的商用JavaEE应用服务器都对JAX-RS提供了支持。
如果对在Dubbo2.6.X中如何开发Rest形式接口不清楚的话,请参考官方用户文档 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/rest.html,官方文档已经写得非常详细了,我就不copy了。不过里面有些东西还是没有说明的,开发过程中也有一些坑,下面通过一个demo示例给大家演示一下。
项目结构还是跟《(2)Dubbo入门使用案例》一样,我还是在上面做的改造。
包含暴露的服务接口,model类,枚举,自定义异常等信息,服务提供者、消费者都会依赖该工程。当前案例中添加了User类、暴露的服务接口UserService。
pom.xml如下:添加了JAX-RS中的注解所需依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wkp</groupId>
<artifactId>dubbo-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>dubbo-interface</name>
<dependencies>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
</project>
User类如下:省略了set、get方法。
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private long id;
private int age;
private String name;
private String sex;
public User() {
super();
}
public User(int age, String name, String sex) {
this(0,age,name,sex);
}
public User(long id,int age, String name, String sex) {
this.id=id;
this.age = age;
this.name = name;
this.sex = sex;
}
}
UserService接口如下:定义了两个方法,addUser为添加用户,getUser为按照userId查找用户。
package com.wkp.service.rest;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.wkp.model.User;
@Path("/user")
public interface UserService {
@Path("/add")
@POST
@Produces({MediaType.APPLICATION_JSON + "; " + MediaType.CHARSET_PARAMETER + "=UTF-8"})
@Consumes({MediaType.APPLICATION_JSON + "; " + MediaType.CHARSET_PARAMETER + "=UTF-8"})
public Long addUser(User user);
@Path("/get/{id:\\d+}")
@GET
@Produces({MediaType.APPLICATION_JSON + "; " + MediaType.CHARSET_PARAMETER + "=UTF-8"})
@Consumes({MediaType.APPLICATION_JSON + "; " + MediaType.CHARSET_PARAMETER + "=UTF-8"})
public User getUser(@PathParam("id")Long id);
}
pom.xml如下:用到的rest支持的jar包不会自动依赖,需要手动添加。
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wkp</groupId>
<artifactId>dubbo-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.wkp</groupId>
<artifactId>dubbo-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.4</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.0.35.Final</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<!-- Dubbo的rest支持 -->
<!-- 如果要使用tomcat server -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-logging-juli</artifactId>
<version>8.0.11</version>
</dependency>
<!-- rest支持 -->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.0.19.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>3.0.19.Final</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<!-- 如果要使用json序列化 -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<version>3.0.19.Final</version>
</dependency>
<!-- 如果要使用xml序列化 -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
<version>3.0.19.Final</version>
</dependency>
<!-- 如果要使用netty server -->
<!-- <dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-netty</artifactId>
<version>3.0.19.Final</version>
</dependency> -->
<!-- 如果要使用Sun HTTP server -->
<!-- <dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jdk-http</artifactId>
<version>3.0.19.Final</version>
</dependency> -->
</dependencies>
</project>
UserService接口的实现类UserServiceImpl如下:没有添加数据库持久化,为了方便用的全局map保存来代替的,使用AtomicLong来生成全局自增id。
package com.wkp.service.rest.impl;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import com.wkp.model.User;
import com.wkp.service.rest.UserService;
public class UserServiceImpl implements UserService {
//存放添加的user
private static final Map<Long, User> userMap=new ConcurrentHashMap<Long, User>();
//生成自增ID
private static final AtomicLong userIdGenerator=new AtomicLong(0);
@Override
public User getUser(Long id) {
return userMap.get(id);
}
@Override
public Long addUser(User user) {
user.setId(userIdGenerator.incrementAndGet());
userMap.put(user.getId(), user);
return user.getId();
}
}
服务提供者配置文件rest-provider.xml如下:对接口暴露了两种协议,
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 具体的实现bean -->
<bean id="userService" class="com.wkp.service.rest.impl.UserServiceImpl" />
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="simple-provider">
<dubbo:parameter key="qos.enable" value="true" />
<dubbo:parameter key="qos.accept.foreign.ip" value="true" />
<dubbo:parameter key="qos.port" value="22222" />
</dubbo:application>
<!-- 使用zookeeper注册中心暴露服务地址(zookeeper单节点时,address的值例如:zookeeper://192.168.74.4:2181) -->
<dubbo:registry address="zookeeper://192.168.74.4:2181?backup=192.168.74.5:2181,192.168.74.6:2181" />
<!-- 多协议 -->
<!-- rest服务端口8080,server为tomcat -->
<dubbo:protocol name="rest" port="8080" contextpath="restApi" server="tomcat"/>
<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880"/>
<!-- 声明需要暴露的服务接口 写操作可以设置retries=0 避免重复调用SOA服务 -->
<dubbo:service retries="0" interface="com.wkp.service.rest.UserService" ref="userService" />
</beans>
服务提供者启动类如下:
package com.wkp.service.rest.provider;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class RestProvider {
@SuppressWarnings("resource")
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "rest-provider.xml" });
context.start();
System.in.read(); // 为保证服务一直开着,利用输入流的阻塞来模拟
}
}
pom.xml如下:消费者也要手动添加rest支持
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wkp</groupId>
<artifactId>dubbo-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.wkp</groupId>
<artifactId>dubbo-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.4</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.0.35.Final</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<!-- rest支持 -->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.0.19.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>3.0.19.Final</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.7</version>
</dependency>
</dependencies>
</project>
服务消费者配置文件rest-consumer.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
<dubbo:application name="simple-consumer">
<dubbo:parameter key="qos.enable" value="true" />
<dubbo:parameter key="qos.accept.foreign.ip" value="true" />
<dubbo:parameter key="qos.port" value="33333" />
</dubbo:application>
<!-- 注册中心地址 -->
<dubbo:registry address="zookeeper://192.168.74.4:2181?backup=192.168.74.5:2181,192.168.74.6:2181" />
<!-- 生成远程服务代理,可以像使用本地bean一样使用demoService 检查级联依赖关系 默认为true 当有依赖服务的时候,需要根据需求进行设置 -->
<dubbo:reference id="userService" check="false" interface="com.wkp.service.rest.UserService" />
</beans>
服务消费者启动调用类如下:里面分别演示了两种服务接口的调用方式
package com.wkp.service.rest.consumer;
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.alibaba.fastjson.JSONObject;
import com.wkp.model.User;
import com.wkp.service.rest.UserService;
public class RestConsumer {
private static String baseUri="http://localhost:8080/restApi";
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException, InterruptedException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"rest-consumer.xml"});
context.start();
//RPC调用
UserService userService = (UserService) context.getBean("userService");
Long userOneId = userService.addUser(new User(20, "张三","男"));
System.out.println("[dubbo调用] 添加用户成功,id:"+userOneId);
User userOne = userService.getUser(userOneId);
System.out.println("[dubbo调用]查找用户成功,user=:"+JSONObject.toJSONString(userOne));
//Rest调用
String userTwoId = post(new User(30, "李四","女"));
System.out.println("[rest调用]添加用户成功,id:"+userTwoId);
String userTwo = get(userTwoId);
System.out.println("[rest调用]查找用户成功,user=:"+userTwo);
System.in.read(); // 为保证服务一直开着,利用输入流的阻塞来模拟
}
public static String post(User user) throws ClientProtocolException, IOException {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpPost request=new HttpPost(baseUri+"/user/add");
request.setHeader("Content-Type", "application/json;charset=UTF-8");
String params = JSONObject.toJSONString(user);
HttpEntity entity=new StringEntity(params, "utf-8");
request.setEntity(entity);
CloseableHttpResponse response = httpClient.execute(request);
int statusCode = response.getStatusLine().getStatusCode();
String resp=null;
if(statusCode==200) {
resp= EntityUtils.toString(response.getEntity());
}
return resp;
}
public static String get(String userId) throws ClientProtocolException, IOException {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpGet request=new HttpGet(baseUri+"/user/get/"+userId);
request.setHeader("Content-Type", "application/json;charset=UTF-8");
CloseableHttpResponse response = httpClient.execute(request);
String resp = parseResponse(response);
return resp;
}
private static String parseResponse(CloseableHttpResponse response) throws IOException {
int statusCode = response.getStatusLine().getStatusCode();
String resp=null;
if(statusCode==200) {
resp= EntityUtils.toString(response.getEntity());
}
return resp;
}
}
调用结果如下所示:
[dubbo调用] 添加用户成功,id:1
[dubbo调用]查找用户成功,user=:{"age":20,"id":1,"name":"张三","sex":"男"}
[rest调用]添加用户成功,id:2
[rest调用]查找用户成功,user=:{"id":2,"age":30,"name":"李四","sex":"女"}
相信看到这里,你也可以用Dubbo开发自己的Rest形式的接口了。如果你想了解更多这方面的案例,请参考Dubbo官方给出的案例工程 incubator-dubbo-samples 中的 dubbo-sample-rest,项目GitHub地址为:https://github.com/apache/incubator-dubbo-samples
笔者在做上面案例的时候还是遇到了好几个坑的,下一节跟大家分享一下,欢迎继续关注呦!
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/u012988901/article/details/85082682
内容来源于网络,如有侵权,请联系作者删除!