dubbo支持多种远程调用方式,例如:dubbo RPC(二进制序列化+tcp协议)、http调用 (二进制序列化+http协议)、hessian(二进制序列化+http协议)、webService(文本序列化+http协议)。
快速入门:
在dubbo中开发一个REST风格的服务会比较简单,下面以一个注册用户的简单服务为例说明。
这个服务要实现的功能是提供如下URL:
http://localhost:8080/user/register
而任何客户端可以将包含用户信息的Json串post到以url来完成用户注册。
服务接口
public class UserService {
void registerUser(User user);
}
服务实现
@Path("users")
public class UserServiceImpl implements UserService {
@POST
@Path("register")
@Consumes({MediaType.APPLICATION_JSON})
public void registerUser(User user) {
// save the user...
}
}
最后在spring配置文件中添加此服务,即完成所有服务开发工作:
<!-- 用rest协议在8080端口暴露服务 -->
<dubbo:protocol name="rest" port="8080"/>
<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="xxx.UserService" ref="userService"/>
<!-- 和本地bean一样实现服务 -->
<bean id="userService" class="xxx.UserServiceImpl" />
在Dubbo中开REST服务主要都是通过JAX-RS的注解来完成配置的,我们完全可以将注解放到服务的接口上,这两种方式是完全等价的。
定制序列化
REST的底层实现会在service的对象和json/xml数据格式之间自动做序列化和反序列化,实现是用JAXB做XML序列化,用Jackson做json序列化,所以在对象上添加JAXB或Jackson的注解即可定制映射。
如定制xml元素的名字:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class User implements Serializable {
@XmlElement(name="username")
private String name;
}
定制对象属性映射到json字段的名字:
public class User implements Serializable {
@JsonProperty("username")
private String name;
}
配置REST server的实现
如果不配置,默认使用jetty,建议在需要高性能场景下采用tomcat,如果你的dubbo系统不是单独启动的进程,而是部署到Java应用服务器中,则建议你采用servlet,dubbo将采用外部应用服务器的servlet容器来做rest server,另外还需要在web.xml中添加以下配置:
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/META-INF/spring/dubbo-demo-provider.xml</param-value>
</context-param>
<listener>
<listener-class>com.alibaba.dubbo.remoting.http.servlet.BootstrapListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
即必须将dubbo的BootstrapListener和DispatcherServlet添加到web.xml,以完成dubbo的REST功能与外部servlet容器的集成。
如果你用spring的ContextLoaderListener来加载spring,则必须保证BootstrapListener配置在ContextLoaderListerner之前,否则dubbo初始化会出错。
获取上下文信息
(1)用@Context
public User getUser(@PathParam("id") Long id, @Context HttpServletRequest request) {
System.out.println("Client address is " + request.getRemoteAddr());
}
(2)RpcContext
public User getUser(@PathParam("id") Long id) {
System.out.println("Client address is " + RpcContext.getContext().getRemoteAddressString());
}
配置Context path
<dubbo:protocol name="rest" port="8888" contextpath="services"/>
@Path("users")
public class UserServiceImpl implements UserService {
@POST
@Path("register")
@Consumes({MediaType.APPLICATION_JSON})
public void registerUser(User user) {
// save the user...
}
}
此进完整的url为
http://localhost:8888/services/users/register
另外,如果你使用servlet,则必须保证这里设置 的port、contextpath与外部应用服务器的端口、DispatcherServlet的Contextpath一致,这里的必须与web.xml中<url-pattern/>完全一致。
配置线程数和IO线程数
<dubbo:protocol name="rest" iothreads="5" threads="100"/>
如果为servlet,这时候启用的是外部服务器,不受dubbo控制,设置了也无效。
用注解取代Spring xml配置
@Service(protocol = "rest")
@Path("users")
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@POST
@Path("register")
@Consumes({MediaType.APPLICATION_JSON})
public void registerUser(User user) {
// save the user
userRepository.save(user);
}
}
服务消费端
(1)non-dubbo->dubbo
这种场景与dubbo本身无关,如使用HttpClent。
(2)dubbo->dubbo
和其他dubbo的远程调用方式一样。
<dubbo:reference id="userService" interface="xxx.UserService"/>
(3)dubbo->non-dubbo
<dubbo:reference id="userService" interface="xxx.UserService" url="rest://api.foo.com/services/"/>
直接配置外部REST服务的url地址即可。
最后欢迎大家访问我的个人网站:1024s