为什么dubbo优点使用ZkClient作为zookeeper的客户端

评论-2688&
本篇主要是来分享从头开始搭建一个dubbo+zookeeper平台的过程,其中会简要介绍下dubbo服务的作用。
& 首先,看下一般网站架构随着业务的发展,逻辑越来越复杂,数据量越来越大,交互越来越多之后的常规方案演进历程。
& 其次,当服务越来越多之后,我们需要做哪些服务治理?
& 最后,是dubbo的架构图
&&&&&& & 注册中心的选择
& dubbo支持多种类型的注册中心:
& Multicast注册中心
& Zookeeper注册中心
& Redis注册中心
& Simple注册中心
& 这里我们选择zookeeper,其实类型的优点缺点可详细查看文档。
& 1:zookeeper的安装,还是采用docker这一招鲜的run命令来安装zookeeper
docker run -dit --name zookeeper
--hostname
zookeeper-host
-v /data:/data -p 2181:2181 jplock/zookeeper:latest
& 2:安装zkui,可以参考来安装,它提供了一个管理界面,可以针对zookeepr的节点值进行CRUD操作,同时也提供了安全认证,按照如下几步就可以完成安装。
& mvn clean install,执行前需要安装java环境,maven环境,执行成功后会生成一个jar文件。
& 将config.cfg复制到上一步生成的jar文件所在目录,然后修改配置文件中的zookeeper地址。
& 执行 jar. ( nohup java -jar zkui-2.0-SNAPSHOT-jar-with-dependencies.jar & ),注意后面的那个&,是指不退出的意思。
& 测试,http://localhost:9090,如能看到如下页面则代表zookeeper安装运行正常。
& 下面是创建dubbo服务以及使用dubbo服务的过程:&& dubbo提供者,创建一个java工程,注意以下几点:
&包依赖,引入如下三个主要的包就可以了,主要是spring,dubbo以及zkclient&&
&dependency&
&groupId&org.springframework&/groupId&
&artifactId&spring-context&/artifactId&
&version&${spring-framework.version}&/version&
&/dependency&
&dependency&
&groupId&com.alibaba&/groupId&
&artifactId&dubbo&/artifactId&
&version&2.4.10&/version&
&exclusions&
&exclusion&
&artifactId&spring&/artifactId&
&groupId&org.springframework&/groupId&
&/exclusion&
&/exclusions&
&/dependency&
&dependency&
&groupId&com.101tec&/groupId&
&artifactId&zkclient&/artifactId&
&version&0.3&/version&
&/dependency&
&定义接口,这里为了演示,简单定义了一个返回产品名称的接口。
public interface IProduct {
String getProductName();
&接口实现&
public class ProductService implements IProduct{
public String getProductName() {
return "jim";
&服务启动函数
加载配置文件
调用context.start()
执行一个不退出程序的操作,这里有很多种做法。
public class App {
private final static Logger logger = LoggerFactory.getLogger(App.class);
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"classpath*:applicationContext.xml");
context.start();
logger.info("dubbo service begin to start");
System.in.read();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
&服务配置文件,这里需要指出的是:
dubbo:service的定义配合了dubbo:annotation,ref="productService",是指定的一个id,实际的实现类通过注解扫描来完成的,并没有在配置文件中指定实现类,后面的消费者配置文件中会有所体现。
dubbo:application中,可以指定logger的实现接口。
dubbo:protocol中,可以指定是否启动访问日志,这个对有时排查线上问题非常有帮助。
&?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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd"
&context:property-placeholder location="classpath*:config.properties"/&
&dubbo:application name="jim" logger="slf4j" /&
&dubbo:registry protocol="zookeeper" address="192.168.21.128:2181" /&
&dubbo:protocol accesslog="true" name="dubbo" port="20880" /&
&dubbo:annotation package="jim" /&
&dubbo:service interface="jim.IProduct" ref="productService"/&
&context:component-scan base-package="jim" /&
&import resource="redis-context.xml"/&
&&&&&&&& && dubbo消费者
&& 消费者配置文件,它的配置相对提供者要简单很多:
指定消费者的名称,这个可以随意,不需要与提供者做任务相关联的匹配。
指定协定类型,zookeeper地址。
指定引用的服务接口,注意这里的id就与服务提供者定义的ref值相同。
&?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.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd"&
&dubbo:application name="consumer-of-jim-app"
&dubbo:registry protocol="zookeeper" address="192.168.21.128:2181"/&
&dubbo:reference interface="jim.IProduct" id="productService" /&
&& 接口注解定义以及接口调用&&&&
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
@Autowired
private IProduct productS
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
String productName=this.productService.getProductName();
model.addAttribute("name", productName);
return "home";
& dubbo admin
& 有一个UI工具可以针对dubbo服务进行管理,可惜我没有在官方文档提供的链接中下载成功,随后从其它地方虽然下载完成了,但在安装部署方面暂时遇到了一定的问题,需要手续研究解决。
&& 正常应该可以看到如下界面:
管理提供者
管理消费者
&&&&&& 服务治理
&&&&&& &&& 经过上面的步骤后,就可以启动服务端以及客户端来验证了。上面只是简单的搭建了dubbo环境以及实现了一个hello world的服务接口,要想使用好dubbo还有好多提供的最佳实践,比如服务治理:
&本文引用:
http://dubbo.io/User+Guide-zh.htm#UserGuide-zh-%E5%A4%9A%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83
http://blog.csdn.net/yinwenjie/article/details/
https://github.com/DeemOpen/zkui
阅读(...) 评论()一、使用dubbo的准备工作
1. zookeeper单节点环境
&&& Demo中选用的zookeeper为zookeeper-3.4.5-cdh5.0.0.tar.gz版本,作为开发环境,在不考虑zookeeper部署多节点的情况下,在本机(windows环境)解压之后,进入解压目录下的conf文件夹,复制一份zoo_sample.cfg文件,修改为zoo.cfg。然后运行bin/zkServer.cmd 启动zookeeper服务。
备注:(1)zookeeper启动会自动读取zoo.cfg文件,该文件主要定义了zookeeper需要暴露的端口,数据和日志的存储路径。
   (2)如果启动cmd之后 闪退,在该cmd中最后一行添加pause,可以查看错误信息。
2.zookeeper分布式部署
&&&&&& 如果保证zookeeper的高可用性,需要部署一个zookeeper集群,这里介绍zookeeper集群在linux中部署的方式。
(1)&&& 在三台机器上分别解压zookeeper-3.4.5-cdh5.0.0.tar.gz包,为了目录的清晰,可以修改解压后文件夹的名称为zookeeper-2181。
(2)&&& 在每台机器的zookeeper解压目录中,创建data和logs两个文件夹,用于zookeeper的数据和日志存放:
(3)&&& 在每台机器的zookeeper解压目录的conf文件夹中,创建一个zoo.cfg文件,文件内容如下:
tickTime=2000
initLimit=5
syncLimit=2
dataDir=/home/nxeop/zookeeper/data
dataLogDir=/home/nxeop/zookeeper/logs
clientPort=2181
server.1= EopApp1:
server.2= EopApp2:
server.3= EopApp2:
maxClientCnxns=60
minSessionTimeout=4000
&&& 注解:
tickTime:心跳时间
initLimit:多少个心跳时间内,允许其他server连接并初始化数据
syncLimit:多少个tickTime内,允许follower节点同步
dataDir:存放内存数据文件目录,根据实际环境修改
dataLogDir:存放日志文件目录,根据实际环境修改
clientPort:监听端口,使用默认2181端口
server.x:配置集群主机信息,[hostname]:[通信端口]:[选举端口],根据自己的主机信息修改
maxClientCnxns:最大并发客户端数,用于防止DOS的,设置为0是不加限制
minSessionTimeout:最小的客户端session超时时间(单位是毫秒)
maxSessionTimeout:最大的客户端session超时时间(单位是毫秒)
EopApp1、EopApp2、EopApp3是三台需要部署zookeeper节点服务器的hostname,这个zoo.cfg文件在集群中所有节点的配置都是一样,直接复制就可以了。
server.1、server.2和server.3 表示三个服务器,每个服务器在zookeeper集群中有一个唯一的id,这个id就是server.x中的这个x。
(4)&&& 最关键的一步,我们需要配置每台服务器上的zookeeper的id。之前已经在每台机器上的zookeeper解压目录中创建了data文件夹和logs文件夹。那么,我们在data文件夹中创建一个文件叫myid,对于第一台服务器,文件的内容为1。依次在各台主机的data目录下生成myid文件设置id值,myid的内容要与前面配置的zoo.cfg中设置的server.x保持一致。
(5)&&& 启动zookeeper:
在三台服务器上依次执行zookeeper目录中:
bin/zkServer.sh start
命令,zookeeper三个节点一次启动。
全部启动完成后,可以执行
bin/zkServer.sh status&&&&&&&&&&&&&&
去查看每个zk节点在集群中的状态。
至此,zookeeper的集群已经部署完成。
示例1:最简单dubbo服务注册与调用
1. 示例场景和思路
&&&&&& 当前实例的设计思路图如下所示:
person-center:人员信息中心,通过dubbo对外提供服务;
person-client:客户端,通过dubbo使用person-center提供的服务;
zookeeper:注册中心,所有的dubbo应用都注册到这上面;
person-interface:一个接口包,定义了人员信息接口和实体:
person-center引用interface包,用于实现这个接口;
person-client引用interface包,使用里面的接口名称去调用dubbo服务。
2.编写person-interface接口包
&&&&&& (1)创建person-interface的maven工程,默认打包方式为jar包。
&&&&&& (2)编写实体类PersonInfo和接口IPersonInfoService,示例代码结构入下所示:
(3)IPersonInfoService定义两个方法:(这里虽然定义了PersonInfo,不过demo1先不使用,只做最简单的接口)
public interface IpersonInfoService {
* 查询全部人员信息
public String queryPersonInfoAll();
* 根据人员编号查询人员信息
public String queryPersonInfoByNumber(String personNumber);
3.编写person-center 服务端
工程参考结构如下:
(1)创建person-center的maven工程,默认打包方式为jar包。
(2)在pom文件中需要添加的核心依赖jar包如下:
&&&&&& a、person-interface,引用公共接口,用于实现这些接口:
&!-- 引入实现编写好的person接口层 --&
&dependency&
&groupId&test.dubbo.interface&/groupId&
&artifactId&person-interface&/artifactId&
&version&0.0.1-SNAPSHOT&/version&
&/dependency&
&& & b、dubbo,引用dubbo依赖,客户端和服务端都使用同一个依赖:
&!-- 引入dubbo框架(服务端、客户端通用) --&
&dependency&
&groupId&com.alibaba&/groupId&
&artifactId&dubbo&/artifactId&
&version&2.8.4&/version&
&exclusions&
&exclusion&
&artifactId&spring&/artifactId&
&groupId&org.springframework&/groupId&
&/exclusion&
&/exclusions&
&/dependency&
&&&&&& c、zkclient,引用zookeeper客户端,dubbo会自动使用zkclient去和zookeeper进行连接:
&!-- 因为dubbo服务端需要注册服务到zk中,因此依赖zkClient包 --&
&dependency&
&groupId&com.github.sgroschupf&/groupId&
&artifactId&zkclient&/artifactId&
&version&0.1&/version&
&/dependency&
(3)编写实现person-interface接口的代码:
&&&&&& 其中,PersonInfoServiceImpl实现了person-interface包中的IPersonInfoService接口的方法:
public class PersonInfoServiceImpl implements IpersonInfoService {
public String queryPersonInfoAll() {
System.out.println("===================================");
System.out.println("接口实现:queryPersonInfoAll()");
System.out.println("===================================");
return "from PersonInfoServiceImpl : some person Info";
public String queryPersonInfoByNumber(String personNumber) {
System.out.println("===================================");
System.out.println("接口实现:queryPersonInfoByNumber(String personNumber)");
System.out.println("===================================");
return "from PersonInfoServiceImpl :" + personNumber + " 's Info.";
(4)把这个person-center工程配置为一个dubbo的应用。
&&&&&& 在工程的src/main/resources下面创建文件(包括文件夹):
META-INF/spring/applicationContext.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.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd"&
备注1:引入dubbo配置相关的xml的命名空间
&!-- 自动扫描注解:通过dubbo实现 --&
&dubbo:annotation package="test.dubbo.*" /&
&!-- 必须加上:dubbo应用的名称 --&
&dubbo:application name="person-center" /&
&!—dubbo应用注册到zk的地址 --&
&dubbo:registry address="zookeeper://127.0.0.1:2181" /&
备注2:应用名称+zookeeper注册地址,让普通应用变成一个dubbo应用。
&!-- 用dubbo协议在20880端口暴露服务 --&
&dubbo:protocol name="dubbo" port="20880" /&
备注3:如果该dubbo应用想成为服务端,那么配置一个dubbo协议的端口。
&!-- 服务端声明需要对外开放提供服务的接口 --&
&dubbo:service interface="test.dubbo.itf.IpersonInfoService"
protocol="dubbo" ref="personInfoService" /&
&!-- 服务端实现接口的bean --&
&bean id="personInfoService"
class="test.dubbo.impl.PersonInfoServiceImpl" /&
备注4:服务端声明需要对外开放的服务接口,并且对接口关联一个实现类。
(5)编写一个启动类StartDubboServer,启动这个dubbo应用。
import com.alibaba.dubbo.container.M
public class StartDubboServer {
public static void main(String[] args) {
* 通过dubbo的启动程序,自动加载一个spring的context文件;
* 配置文件默认指定路径为 resources/META-INF/spring/applicationContext.xml
Main.main(null);
  通过dubbo提供的一个容器启动工具Main,可以启动一个spring的context容器,并且如果不指定配置文件的话,会自动找如下路径的文件:resources/META-INF/spring/applicationContext.xml
找到spring的xml文件后,容器加载dubbo相关配置,自动启动一个dubbo服务。启动成功后效果如下:
  这个时候,从zookeeper中可以看到,dubbo节点自动创建,并且有一个接口服务已经登记到了dubbo节点下,此时:该接口节点下面consumer节点为空,没有消费方,provider节点有1个子节点,就是我们刚刚启动的那个服务端:
至此,一个dubbo的服务端已经成功创建完成。
4.编写person-client 客户端
工程参考结构如下:
(1)创建person-center的maven工程,默认打包方式为jar包。
(2)在pom文件中需要添加的核心依赖和服务端一模一样,不过person-interface这个jar包的依赖是用于接口的调用;
(3)编写一个使用person-interface接口的代码,person-interface接口通过注入的方式引用:
public class CheckPersonStatus {
* 这个bean的实现来源于dubbo的服务
@Autowired
private IpersonInfoService personInfoS
public String checkAllPersonStatus() {
return personInfoService.queryPersonInfoAll();
public String checkPersonStatusByPersonNumber(String personNumber) {
return personInfoService.queryPersonInfoByNumber(personNumber);
(4)把这个person-center工程配置为一个dubbo的应用。
&?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.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd"&
备注1:引入dubbo配置相关的xml的命名空间
&!-- 自动扫描注解:通过dubbo实现 --&
&dubbo:annotation package="test.dubbo.*" /&
&!-- 必须加上:dubbo应用的名称 --&
&dubbo:application name="person-client" /&
&!—dubbo应用注册的zk地址 --&
&dubbo:registry address="zookeeper://127.0.0.1:2181" /&
备注2:应用名称+zookeeper注册地址,让普通应用变成一个dubbo应用。
&!-- 注册需要使用的dubbo服务,通过interface指定服务接口 --&
&dubbo:reference id="personInfoService" interface="test.dubbo.itf.IpersonInfoService"
timeout="10000" check="false" /&
备注2:dubbo应用作为一个服务使用者,只需要声明需要的接口服务即可。
所有dubbo的应用都需要:
a、& 添加dubbo应用的名称;
b、 添加dubbo应用注册的zookeeper的地址;
对于dubbo的应用:作为一个服务端:
a、添加对外开放的端口号;
b、添加需要开放的接口以及实现;
对于dubbo的应用:作为一个客户端端:
a、添加需要使用的接口;
(5)启动这个dubbo应用,为了使用方便,通过applicationContext进行spring的启动:
public class MainClientRunner {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"META-INF/spring/applicationContext.xml");
* 启动spring容器,同时也会启动dubbo的客户端
context.start();
* 获取bean
CheckPersonStatus checkPersonStatus = (CheckPersonStatus) context.getBean("checkPersonStatus");
/** 调用checkPersonStatus,checkPersonStatus调用了dubbo服务 **/
String allInfo = checkPersonStatus.checkAllPersonStatus();
String oneInfo = checkPersonStatus.checkPersonStatusByPersonNumber("");
System.out.println(allInfo);
System.out.println(oneInfo);
Thread.sleep(3600 * 24);
} catch (InterruptedException e) {
e.printStackTrace();
* 关闭spring的容器
context.close();
至此为止,一个dubbo的客户端已经完成。
客户端运行效果如下:
这个时候,服务端的显示如下:
说明客户端调用的dubbo服务,服务的实现,是在dubbo服务端完成的。
Zookeeper中的dubbo节点如下显示:
可以看出,此时,该接口增加了一个消费者。
示例2:dubbo集群实验
Dubbo服务的分布式主要体现在两个方面:
(1)&&& 多个dubbo应用,可以为同一个接口提供服务。
这个意思就是说,我们编写了一个dubbo应用person-center,对外提供了一个test.dubbo.itf.IpersonInfoService这个接口,那么我们可以部署任意多个person-center服务端并且配置为同一套zookeeper环境,所有的服务端,都会注册到这个zookeeper中,也就意味着有多个provider提供了这个接口服务。直接避免了单点故障,而且能够线性提高接口服务的性能。
(2)&&& 复杂业务系统,拆分成多个基于dubbo服务的业务子系统。
比如对于一个业务系统,可以拆分成多个子系统,子系统对外通过dubbo进行服务交互,实现功能上的分布式构建,降低系统耦合性,而且可以通过多节点,对每个功能实现集群构建。
1. 多节点dubbo服务实验
(1)给person-center这个服务端添加一个调用次数统计的代码:
通过统计调用次数,可以观察多个服务提供方的负载均衡情况。
(2)用过eclipse启动person-center服务端,此时配置文件中,提供服务的端口号为20880。
(3) 分别修改端口号为2之后再次启动服务端。这样,person-center这个服务端已经启动了三个节点,从zookeeper中能看到:
也就是说,对于接口test.dubbo.itf.IPersonInfoService具有三个服务提供方同时提供。
(4)客户端调用:客户端通过一个for循环持续调用这个接口:
&&&&&& 启动客户端之后,客户端会循环调用服务端1000次,这个时候,我们观察每一个服务端的调用统计情况:
当客户端停止调用时,三个服务端分别被调用了338、335、327次,说明,三个节点的调用基本上是负载均衡。
&&&&&& 也就是说,dubbo的服务端集群的负载均衡是在客户端完成的,对于服务端来说是没有感知,集群中每个节点之间是透明的,不存在类似zookeeper的leader和follower的概念。
示例3:dubbo构建REST服务
1. 完善person-interface接口包
之前我们创建的person-interface是一个纯粹的接口代码包,只能作为一个普通的接口,现在我们要把这个接口改造成为可以额外开放成为REST服务的一个接口包。
(1)pom文件中添加2个依赖javax.ws.rs-api和dubbo:
&dependency&
&groupId&javax.ws.rs&/groupId&
&artifactId&javax.ws.rs-api&/artifactId&
&version&2.0&/version&
&/dependency&
这个依赖主要是定义了REST服务接口的注解。
Dubbo的具体依赖和上文是一样的。
(3)&&& 改造接口:
代码中黄色背景部分是新增内容,下面对新增内容一一介绍如下:
package test.dubbo.
import javax.ws.rs.C
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.P
import javax.ws.rs.PathP
import javax.ws.rs.P
import com.alibaba.dubbo.rpc.protocol.rest.support.ContentT
* @author ShengGang 人员数据操作接口
@Path("personInfoService")
@Consumes({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8})
@Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8})
public interface IpersonInfoService {
* 查询全部人员信息
@Path("queryPersonInfoAll")
public String queryPersonInfoAll();
* 根据人员编号查询人员信息
@Path("queryPersonInfoByNumber/{personNumber}")
public String queryPersonInfoByNumber(@PathParam("personNumber") String personNumber);
“@Path”,类似于webMVC中的@RequestMapping, @Path(“personInfoService”)放在了接口类上面,当访问这个接口的方法时,相对的路径则是/personInfoService,也就是说,当这个接口开放为REST服务的时候,请求url就是 ;
“@Consumes”、“@Produces”,分别指定这个接口的消费方和请求需要接收和发送哪种类型的数据,ContentType里面可以选择JSON或者是XML。如果是JSON,那么REST框架会自动进行对象和JSON格式的转换。
“@Get”、“@Post”,指定具体的接口方法暴露为REST服务的时候是Get请求还是Post请求;
“@Path("queryPersonInfoByNumber/{personNumber}")”,这个就是标准的REST风格的URL的定义方法。请求的参数是放到URL中,{personNumber}是指,这个路径会对应着这个方法的参数名。如果personNumber为,那么请求的路径就是
http://localhost:9090/personInfoService/queryPersonInfoByNumber/
“@PathParam(“personNumber”)”,这个注解是可选的,可以指定这个参数的别名。
2. 改造person-center服务端
这个服务端的改造比interface接口包改造要简单多,在之前的配置文件基础上额外增加二个配置即可:开放一个REST服务端口,让之前的接口支持REST协议。
(1)&&& pom文件中添加如下依赖。
&!-- 通过dubbo提供rest服务,需要引入resteasy框架 --&
&dependency&
&groupId&org.jboss.resteasy&/groupId&
&artifactId&resteasy-client&/artifactId&
&version&3.0.7.Final&/version&
&/dependency&
&dependency&
&groupId&org.mortbay.jetty&/groupId&
&artifactId&jetty&/artifactId&
&version&6.1.26&/version&
&/dependency&
&!-- 数据bean的校验框架 --&
&dependency&
&groupId&org.glassfish.hk2.external&/groupId&
&artifactId&bean-validator&/artifactId&
&version&2.4.0&/version&
&/dependency&
这些依赖的作用分别是
resteasy-client:提供REST服务的封装;
jetty:开放HTTP服务;
bean-validator:校验入参和出参的bean;
(2)&&& 在配置文件中添加额外添加一些配置:
标记的第一行意思是,这个dubbo应用开放了REST协议,并且端口号为9090。开放的http服务是通过jetty完成的,“contextpath”则是指定了根路径。
如果需要调用REST服务,则请求路径为:
http://localhost:9090/service/personInfoService/queryPersonInfoAll
&&&&&& 标记的第二行意思是,这个接口会同时支持dubbo和rest两种协议,既可以按照一般的dubbo的调用方式去使用这个接口,也可以通过HTTP进行REST服务的调用。
&&&&&& 最简单的验证REST服务是否正确开放的方法是,直接通过浏览器去访问开放的REST服务地址:
&&&&&& 访问GET请求的接口:
&&&&&& GET请求在浏览器中响应正常。
&&&&&& 访问POST请求的接口:
&&&&&& POST请求在浏览器中响应为空,控制台会提示405,意思是该URL只会接收POST请求,而不会接收GET请求。
示例4:dubbo服务使用数据库
&&&&&& 主要改造的工程为person-center服务端,让这个dubbo服务端真正连接数据库,通过接口返回数据库数据。
1.&&&&& 添加maven依赖
&!-- 引入spring的jdbc --&
&dependency&
&groupId&org.springframework&/groupId&
&artifactId&spring-jdbc&/artifactId&
&version&${org.springframework-version}&/version&
&/dependency&
&!-- 使用阿里的druid数据源 --&
&dependency&
&groupId&com.alibaba&/groupId&
&artifactId&druid&/artifactId&
&version&0.2.8&/version&
&exclusions&
&exclusion&
&artifactId&tools&/artifactId&
&groupId&com.alibaba&/groupId&
&/exclusion&
&exclusion&
&artifactId&jconsole&/artifactId&
&groupId&com.alibaba&/groupId&
&/exclusion&
&/exclusions&
&/dependency&
&!-- mysql的连接器 --&
&dependency&
&groupId&mysql&/groupId&
&artifactId&mysql-connector-java&/artifactId&
&version&5.1.21&/version&
&/dependency&
在person-center项目的pom.xml中,添加如下maven依赖:
spring-jdbc.jar提供了jdbcTemplate的数据库操作api;
druid.jar为阿里的数据源;
mysql-connector-java.jar为mysql的java连接驱动;
2.&&&&& 修改applicationContext.xml文件
修改person-interface下面的META-INF/spring/applicationContext.xml文件,添加如下bean的配置:
&!-- 指定spring需要加载的配置文件 --&
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"&
&property name="location" value="classpath:config.properties" /&
&!-- 采用druid的数据源 --&
&bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close"&
&property name="url" value="${jdbc.url}" /&
&property name="username" value="${jdbc.username}" /&
&property name="password" value="${jdbc.password}" /&
&property name="initialSize" value="${jdbc.initialSize}" /&
&property name="maxActive" value="${jdbc.maxActive}" /&
&property name="testWhileIdle" value="${jdbc.testWhileIdle}" /&
&property name="validationQuery" value="${jdbc.validationQuery}" /&
&!-- jdbcTemplate --&
&bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"&
&property name="dataSource" ref="dataSource" /&
和之前的spring文件相比,主要添加了三个bean:
(1)&&& PropertySourcesPlaceholderConfigurer:这个bean指定了工程路径里面的resources/config.properties文件,那么spring的xml文件中所有的属性配置都通过配置文件去读取和修改;
(2)&&& DataSource:配置了一个数据源,指定了url、username和passwd等数据库连接相关配置;
(3)&&& jdbcTemplate:由spring提供的一个jdbc操作API,可以通过这个实例轻松进行数据库增删改查等操作;
3.&&&&& 创建dao层
(1)&&& 在工程中添加一个dao的package,用于编写dao层,工程结构如下:
(2)编写RowMapper类
由于没有采用Hibernate等持久层框架,而是直接采用的jdbcTemplate操作数据库,因此并没有把数据库字段和实体类PersonInfo进行一一映射。所以,我们需要编写一个RowMapper类把数据库的数据字段一一映射成为PersonInfo的字段。该类主要继承了spring的RowMapper接口,代码如下:
package test.dubbo.dao.
import java.sql.ResultS
import java.sql.SQLE
import org.springframework.jdbc.core.RowM
import test.dubbo.entity.PersonI
public class PersonInfoRowMapper implements RowMapper&PersonInfo& {
public PersonInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
PersonInfo info = new PersonInfo();
info.setPersonNumber(rs.getString("person_number"));
info.setPersonAddr(rs.getString("person_address"));
info.setPersonName(rs.getString("person_name"));
info.setPersonPhoneNumber(rs.getString("person_phone_number"));
info.setPersonStatus(rs.getString("person_status"));
(3)&&& 编写PersonInfoDao类
package test.dubbo.
import java.util.L
import org.springframework.beans.factory.annotation.A
import org.springframework.jdbc.core.JdbcT
import org.springframework.stereotype.R
import test.dubbo.dao.wrapper.PersonInfoRowM
import test.dubbo.entity.PersonI
@Repository
public class PersonInfoDao {
@Autowired
private JdbcTemplate jdbcT
public PersonInfo queryPersonInfo(String personNumber) {
String sql = "select * from person_info where person_number = ?";
return jdbcTemplate.queryForObject(sql, new PersonInfoRowMapper(), personNumber);
public List&PersonInfo& queryPersonInfoList() {
String sql = "select * from person_info";
return jdbcTemplate.query(sql, new PersonInfoRowMapper());
PersonInfoDao使用了jdbcTemplate,从数据库进行读写操作,代码如下:
这里主要通过jdbcTemplate执行了queryForObject和query两个操作,因为我们用了之前编写的继承了RowMapper接口的PersonInfoRowMapper类,因此,查询结果直接返回成了PersonInfo对象。
4.&&&&& 修改Service层的实现类
主要参考代码:
public class PersonInfoServiceImpl implements IpersonInfoService {
private static final AtomicInteger count = new AtomicInteger(0);
@Autowired
private PersonInfoDao personInfoD
private static final String ERROR_INFO = "{\"errorCode\":\"-1\"}";
public String queryPersonInfoAll() {
System.out.println("===================================");
System.out.println("接口实现:queryPersonInfoAll()");
List&PersonInfo& infoList = personInfoDao.queryPersonInfoList();
String rtnI
rtnInfo = JSON.json(infoList);
} catch (IOException e) {
rtnInfo = ERROR_INFO;
e.printStackTrace();
System.out.println("===================================");
return rtnI
public String queryPersonInfoByNumber(String personNumber) {
count.incrementAndGet();
System.out.println("===================================");
System.out.println("接口实现:queryPersonInfoByNumber(String personNumber)");
System.out.println("接口被调用了"+count.get()+"次。");
PersonInfo personInfo = personInfoDao.queryPersonInfo(personNumber);
String rtnI
rtnInfo = JSON.json(personInfo);
} catch (IOException e) {
rtnInfo = ERROR_INFO;
e.printStackTrace();
System.out.println("===================================");
return rtnI
代码注意事项如下:
(1)&&& service层注入了personInfoDao这个实例;
(2)&&& 通过调用personInfoDao中的方法,获取到PersonInfo对象以及对象的List,但是我们需要把对象转成json格式,这里采用阿里的JSON包---
com.alibaba.dubbo.common.json.*
到此为止,dubbo服务端使用数据库部分已经改造完成。
示例5:通过dubbo构建复杂业务场景
1.&&&&& 模拟的场景结构图
这里,作为模拟场景,我们有两个dubbo服务的提供方,person-center和product-center,这两个dubbo应用分别表示两个独立的系统,但是都注册到同一套zookeeper注册中心。order-system-service表示一个第三方综合系统,会使用person-center和product-center两个系统的接口,同时,自己会对外开放自己的dubb/REST接口。
具体的代码可以参考附件内容,里面所有的配置都是之前已经提到过的内容。
其他:常见异常问题及解决
1.&&&&& 启动dubbo服务端后连接zookeeper出现如下异常:
INFO : org.apache.zookeeper.ZooKeeper - Client environment:os.name=Windows 7
INFO : org.apache.zookeeper.ZooKeeper - Client environment:os.arch=amd64
INFO : org.apache.zookeeper.ZooKeeper - Client environment:os.version=6.1
INFO : org.apache.zookeeper.ZooKeeper - Client environment:user.name=zhaijj
INFO : org.apache.zookeeper.ZooKeeper - Client environment:user.home=C:\Users\zhaijj
INFO : org.apache.zookeeper.ZooKeeper - Client environment:user.dir=D:\workdir\person-center
INFO : org.apache.zookeeper.ZooKeeper - Initiating client connection, connectString=192.168.159.5:2181 sessionTimeout=60000 watcher=org.I0Itec.zkclient.ZkClient@2a2b2bd1
INFO : org.apache.zookeeper.ClientCnxn - Opening socket connection to server /192.168.159.5:2181
INFO : org.I0Itec.zkclient.ZkEventThread - Terminate ZkClient event thread.
INFO : org.apache.zookeeper.ClientCnxn - Socket connection established to 192.168.159.5/192.168.159.5:2181, initiating session
INFO : org.apache.zookeeper.ClientCnxn - Session establishment complete on server 192.168.159.5/192.168.159.5:2181, sessionid = 0x158ced3a4380008, negotiated timeout = 40000
INFO : org.apache.zookeeper.ZooKeeper - Session: 0x158ced3a4380008 closed
INFO : org.apache.zookeeper.ClientCnxn - EventThread shut down
org.I0Itec.zkclient.exception.ZkTimeoutException: Unable to connect to zookeeper server within timeout: 5000
at org.I0Itec.zkclient.ZkClient.connect(ZkClient.java:876)
at org.I0Itec.zkclient.ZkClient.&init&(ZkClient.java:98)
at org.I0Itec.zkclient.ZkClient.&init&(ZkClient.java:92)
at org.I0Itec.zkclient.ZkClient.&init&(ZkClient.java:80)
at com.alibaba.dubbo.remoting.zookeeper.zkclient.ZkclientZookeeperClient.&init&(ZkclientZookeeperClient.java:26)
  然而,zookeeper是正常的,排除任何网络、防火墙原因。
  原因:zkClient客户端版本过低,配置的是0.1,引用的zookeeper的jar包是3.3.3,然而服务端的zookeeper版本比较高,达到3.4.6。
  解决方式:升高zkClient的版本:
&dependency&
&groupId&com.101tec&/groupId&
&artifactId&zkclient&/artifactId&
&version&0.9&/version&
&/dependency&
这个最高版本的zkClient用的是zookeeper-3.4.8.jar 。更换包后,正常运行。
阅读(...) 评论()}

我要回帖

更多关于 dubbo优点 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信