- 安装注册中心:Zookeeper、Dubbox自带的dubbo-registry-simple;
- 安装DubboKeeper监控:https://github.com/dubboclub/dubbokeeper;
以上两点准备,不是本文重点,不做详细介绍,安装比较简单,自行查阅相关资料学习。
创建Maven模块:msa-demo-api
msa-demo-api:配置pom.xml
<dependency>
<groupId>com.alibabagroupId>
<artifactId>dubboartifactId>
<version>2.8.4version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>org.jboss.resteasygroupId>
<artifactId>resteasy-jaxrsartifactId>
<version>3.0.7.Finalversion>
dependency>
<dependency>
<groupId>org.jboss.resteasygroupId>
<artifactId>resteasy-clientartifactId>
<version>3.0.7.Finalversion>
dependency>
<dependency>
<groupId>javax.validationgroupId>
<artifactId>validation-apiartifactId>
<version>1.0.0.GAversion>
dependency>
<dependency>
<groupId>org.jboss.resteasygroupId>
<artifactId>resteasy-jackson-providerartifactId>
<version>3.0.7.Finalversion>
dependency>
<dependency>
<groupId>org.jboss.resteasygroupId>
<artifactId>resteasy-jaxb-providerartifactId>
<version>3.0.7.Finalversion>
dependency>
<dependency>
<groupId>org.jboss.resteasygroupId>
<artifactId>resteasy-nettyartifactId>
<version>3.0.7.Finalversion>
dependency>
<dependency>
<groupId>org.jboss.resteasygroupId>
<artifactId>resteasy-jdk-httpartifactId>
<version>3.0.7.Finalversion>
dependency>
<dependency>
<groupId>org.apache.tomcat.embedgroupId>
<artifactId>tomcat-embed-coreartifactId>
<version>8.0.11version>
dependency>
<dependency>
<groupId>org.apache.tomcat.embedgroupId>
<artifactId>tomcat-embed-logging-juliartifactId>
<version>8.0.11version>
dependency>
<dependency>
<groupId>com.esotericsoftware.kryogroupId>
<artifactId>kryoartifactId>
<version>2.24.0version>
dependency>
<dependency>
<groupId>de.javakaffeegroupId>
<artifactId>kryo-serializersartifactId>
<version>0.26version>
dependency>
<dependency>
<groupId>de.ruedigermoellergroupId>
<artifactId>fstartifactId>
<version>1.55version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-coreartifactId>
<version>2.3.3version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.3.3version>
dependency>
以上POM配置,从dubbox-2.8.4开始,所有依赖库的使用方式将和dubbo原来的一样:即如果要使用REST、Kyro、FST、Jackson等功能,需要用户自行手工添加相关的依赖。
定义接口:UserService.java
/**
* @author TaoBangren
* @version 1.0
* @since 2017/5/17 上午9:26
*/
public interface UserService {
User getUser(Long id);
Long registerUser(User user);
}
定义REST接口:AnotherUserRestService.java
package com.alibaba.dubbo.demo.user.facade;
import com.alibaba.dubbo.demo.user.User;
import com.alibaba.dubbo.rpc.protocol.rest.support.ContentType;
import javax.validation.constraints.Min;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
/**
* @author TaoBangren
* @version 1.0
* @since 2017/5/17 上午9:26
*/
// 在Dubbo中开发REST服务主要都是通过JAX-RS的annotation来完成配置的,
// 在上面的示例中,我们都是将annotation放在服务的实现类中。但其实,我
// 们完全也可以将annotation放到服务的接口上,这两种方式是完全等价的.
//
// 在一般应用中,我们建议将annotation放到服务实现类,这样annotation和
// java实现代码位置更接近,更便于开发和维护。另外更重要的是,我们一般倾向
// 于避免对接口的污染,保持接口的纯净性和广泛适用性。
// 但是,如后文所述,如果我们要用dubbo直接开发的消费端来访问此服务,则annotation必须放到接口上。
// 如果接口和实现类都同时添加了annotation,则实现类的annotation配置会生效,接口上的annotation被直接忽略。
@Path("u")
@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
@Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8})
public interface AnotherUserRestService {
@GET
@Path("{id : \\d+}")
// 在一个REST服务同时对多种数据格式支持的情况下,根据JAX-RS标准,
// 一般是通过HTTP中的MIME header(content-type和accept)来指定当前想用的是哪种格式的数据。
// @Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8})
// 但是在dubbo中,我们还自动支持目前业界普遍使用的方式,即用一个URL后缀(.json和.xml)来指定
// 想用的数据格式。例如,在添加上述annotation后,直接访问http://localhost:8888/users/1001.json
// 则表示用json格式,直接访问http://localhost:8888/users/1002.xml则表示用xml格式,
// 比用HTTP Header更简单直观。Twitter、微博等的REST API都是采用这种方式。
// 如果你既不加HTTP header,也不加后缀,则dubbo的REST会优先启用在以上annotation定义中排位最靠前的那种数据格式。
// 注意:这里要支持XML格式数据,在annotation中既可以用MediaType.TEXT_XML,也可以用MediaType.APPLICATION_XML,
// 但是TEXT_XML是更常用的,并且如果要利用上述的URL后缀方式来指定数据格式,只能配置为TEXT_XML才能生效。
User getUser(@PathParam("id") @Min(1L) Long id);
@POST
@Path("register")
RegistrationResult registerUser(User user);
}
定义实体:User.java
package com.alibaba.dubbo.demo.user;
import lombok.Data;
import org.codehaus.jackson.annotate.JsonProperty;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
/**
* @author TaoBangren
* @version 1.0
* @since 2017/5/17 上午9:26
*/
// 由于JAX-RS的实现一般都用标准的JAXB(Java API for XML Binding)来序列化和反序列化XML格式数据,
// 所以我们需要为每一个要用XML传输的对象添加一个类级别的JAXB annotation(@XmlRootElement) ,否则序列化将报错。
@Data
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class User implements Serializable {
@NotNull
@Min(1L)
private Long id;
// REST的底层实现会在service的对象和JSON/XML数据格式之间自动做序列化/反序列化。
// 但有些场景下,如果觉得这种自动转换不满足要求,可以对其做定制。
// Dubbo中的REST实现是用JAXB做XML序列化,用Jackson做JSON序列化,
// 所以在对象上添加JAXB或Jackson的annotation即可以定制映射。
@JsonProperty("username")
@XmlElement(name = "username")
@NotNull
@Size(min = 6, max = 50)
private String name;
}
定义REST响应结果实体:RegistrationResult.java
package com.alibaba.dubbo.demo.user.facade;
import lombok.Data;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
/**
* @author TaoBangren
* @version 1.0
* @since 2017/5/17 上午9:26
*/
// 此外,如果service方法中的返回值是Java的 primitive类型(如int,long,float,double等),
// 最好为它们添加一层wrapper对象,因为JAXB不能直接序列化primitive类型。这样不但能够解决XML序列化的问题,
// 而且使得返回的数据都符合XML和JSON的规范。
// 这种wrapper对象其实利用所谓Data Transfer Object(DTO)模式,采用DTO还能对传输数据做更多有用的定制。
@Data
@XmlRootElement
public class RegistrationResult implements Serializable {
private Long id;
}
创建Maven模块:msa-demo-provider
msa-demo-provider:配置pom.xml
<dependency>
<groupId>com.alibabagroupId>
<artifactId>msa-demo-apiartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
实现UserService接口:UserServiceImpl.java
package com.alibaba.dubbo.demo.user;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.atomic.AtomicLong;
/**
* @author TaoBangren
* @version 1.0
* @since 2017/5/17 上午9:26
*/
@Slf4j
public class UserServiceImpl implements UserService {
private final AtomicLong idGen = new AtomicLong();
public User getUser(Long id) {
User user = new User();
user.setId(id);
user.setName("username" + id);
return user;
}
public Long registerUser(User user) {
// System.out.println("Username is " + user.getName());
return idGen.incrementAndGet();
}
}
实现REST接口AnotherUserRestService:AnotherUserRestServiceImpl.java
package com.alibaba.dubbo.demo.user.facade;
import com.alibaba.dubbo.demo.user.User;
import com.alibaba.dubbo.demo.user.UserService;
import com.alibaba.dubbo.rpc.RpcContext;
import lombok.extern.slf4j.Slf4j;
/**
* @author TaoBangren
* @version 1.0
* @since 2017/5/17 上午9:26
*/
@Slf4j
public class AnotherUserRestServiceImpl implements AnotherUserRestService {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public User getUser(Long id) {
System.out.println("Client name is " + RpcContext.getContext().getAttachment("clientName"));
System.out.println("Client impl is " + RpcContext.getContext().getAttachment("clientImpl"));
return userService.getUser(id);
}
public RegistrationResult registerUser(User user) {
Long id = userService.registerUser(user);
RegistrationResult registrationResult = new RegistrationResult();
registrationResult.setId(id);
return registrationResult;
}
}
Dubbox与Spring集成配置:msa-demo-provider.xml
xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="msa-demo-provider" owner="tbr" organization="tbr"/>
<dubbo:monitor address="x.x.x.x:20884"/>
<dubbo:registry protocol="zookeeper" address="x.x.x.x:2181,x.x.x.x:2181,x.x.x.x:2181"/>
<dubbo:protocol name="dubbo" port="20880" serialization="kryo"/>
<dubbo:protocol name="rest" port="8888" threads="500" contextpath="services" server="tomcat" accepts="500"
extension="com.alibaba.dubbo.demo.extension.TraceInterceptor,
com.alibaba.dubbo.demo.extension.TraceFilter,
com.alibaba.dubbo.demo.extension.ClientTraceFilter,
com.alibaba.dubbo.demo.extension.DynamicTraceBinding,
com.alibaba.dubbo.demo.extension.CustomExceptionMapper,
com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter"/>
<dubbo:protocol name="http" port="8889"/>
<dubbo:protocol name="hessian" port="8890"/>
<dubbo:protocol name="webservice" port="8892"/>
<dubbo:service interface="com.alibaba.dubbo.demo.user.UserService" ref="userService" protocol="dubbo" group="xmlConfig"/>
<dubbo:service interface="com.alibaba.dubbo.demo.user.facade.AnotherUserRestService" ref="anotherUserRestService" protocol="rest" timeout="2000" connections="100" validation="true"/>
<bean id="userService" class="com.alibaba.dubbo.demo.user.UserServiceImpl"/>
<bean id="anotherUserRestService" class="com.alibaba.dubbo.demo.user.facade.AnotherUserRestServiceImpl">
<property name="userService" ref="userService"/>
bean>
beans>
#dubbo.container=log4j,spring
#dubbo.application.name=demo-provider
#dubbo.application.owner=
#dubbo.registry.address=multicast://224.5.6.7:1234
#dubbo.registry.address=zookeeper://127.0.0.1:2181
#dubbo.registry.address=redis://127.0.0.1:6379
#dubbo.registry.address=dubbo://127.0.0.1:9090
#dubbo.monitor.protocol=registry
#dubbo.protocol.name=dubbo
#dubbo.protocol.port=20880
#dubbo.service.loadbalance=roundrobin
#dubbo.log4j.file=logs/msa-demo-provider.log
#dubbo.log4j.level=INFO
#dubbo.log4j.subdirectory=20880
dubbo.application.logger=slf4j
dubbo.spring.config=classpath*:msa-*.xml
定义服务启动类:
package com.alibaba.dubbo.demo.provider;
/**
* @author TaoBangren
* @version 1.0
* @since 2017/5/17 上午9:26
*/
public class DemoProvider {
public static void main(String[] args) {
com.alibaba.dubbo.container.Main.main(args);
}
}
执行main方法启动,看到以下日志输出时,msa-demo-provider启动成功:
查看DubboKeeper监控大盘,msa-demo-provider发布服务成功,可以看到我们发布的两个接口:
创建Maven模块:msa-demo-client
msa-demo-client:配置pom.xml
<dependency>
<groupId>com.alibabagroupId>
<artifactId>msa-demo-apiartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
Dubbox与Spring集成配置:msa-demo-client.xml
xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:reference id="userService" interface="com.alibaba.dubbo.demo.user.UserService" group="xmlConfig"/>
<dubbo:reference id="anotherUserRestService" interface="com.alibaba.dubbo.demo.user.facade.AnotherUserRestService"/>
beans>
创建Maven模块:msa-demo-consumer
msa-demo-consumer:配置pom.xml
<dependency>
<groupId>com.jeasygroupId>
<artifactId>msa-demo-clientartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
创建消费端测试类:DemoAction.java
package com.alibaba.dubbo.demo;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.demo.user.User;
import com.alibaba.dubbo.demo.user.UserService;
import com.alibaba.dubbo.demo.user.facade.AnotherUserRestService;
/**
* @author TaoBangren
* @version 1.0
* @since 2017/5/17 上午9:26
*/
public class DemoAction {
private UserService userService;
private AnotherUserRestService anotherUserRestService;
public void setUserService(final UserService userService) {
this.userService = userService;
}
public void setAnotherUserRestService(final AnotherUserRestService anotherUserRestService) {
this.anotherUserRestService = anotherUserRestService;
}
public void start() throws Exception {
User user = new User();
user.setId(1L);
user.setName("larrypage");
System.out.println("SUCCESS: registered user with id by rest" + anotherUserRestService.registerUser(user).getId());
System.out.println("SUCCESS: registered user with id " + userService.registerUser(user));
RpcContext.getContext().setAttachment("clientName", "demo");
RpcContext.getContext().setAttachment("clientImpl", "dubbox rest");
System.out.println("SUCCESS: got user by rest" + anotherUserRestService.getUser(1L));
System.out.println("SUCCESS: got user " + userService.getUser(1L));
}
}
Dubbox与Spring集成配置:msa-demo-consumer.xml
xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="msa-demo-consumer" owner="tbr" organization="tbr"/>
<dubbo:registry protocol="zookeeper" address="x.x.x.x:2181,x.x.x.x:2181,x.x.x.x:2181"/>
<dubbo:monitor address="x.x.x.x:20884"/>
<bean class="com.alibaba.dubbo.demo.DemoAction" init-method="start">
<property name="userService" ref="userService"/>
<property name="anotherUserRestService" ref="anotherUserRestService"/>
bean>
beans>
配置dubbo.properties
#dubbo.container=log4j,spring
#dubbo.application.name=demo-consumer
#dubbo.application.owner=
#dubbo.registry.address=multicast://224.5.6.7:1234
#dubbo.registry.address=zookeeper://127.0.0.1:2181
#dubbo.registry.address=redis://127.0.0.1:6379
#dubbo.registry.address=dubbo://127.0.0.1:9090
#dubbo.monitor.protocol=registry
#dubbo.log4j.file=logs/msa-demo-consumer.log
#dubbo.log4j.level=INFO
dubbo.application.logger=slf4j
dubbo.spring.config=classpath*:msa-*.xml
定义消费启动类:
package com.jeasy;
/**
* @author TaoBangren
* @version 1.0
* @since 2017/5/17 上午9:26
*/
public class DemoConsumer {
public static void main(String[] args) {
com.alibaba.dubbo.container.Main.main(args);
}
}
执行main方法启动,看到以下日志输出时,msa-demo-consumer启动成功:
同时服务端会输出服务调用日志信息,并调用成功,如下:
模块 | 描述 | 是否必须 |
---|---|---|
msa-xxx-api | 定义接口&实体 | 必须 |
msa-xxx-provider | 依赖api模块,实现服务接口,提供服务 | 必须 |
msa-xxx-client | 依赖api模块,Spring配置文件&测试用例,提供给第三方调用服务使用 | 必须 |
msa-xxx-consumer | 依赖client模块,建议保留该模块,避免client模块直接与应用方紧耦合 | 可选 |