Dubbo分布式服务开发
Apache Dubbo™ (incubating)是一款高性能Java RPC框架,采用netty通信。
Dubbo 采用全 Spring 配置方式,透明化接入应用,对应用没有任何 API 侵入,只需用 Spring 加载 Dubbo 的配置即可,Dubbo 基于 Spring 的 Schema 扩展 进行加载。
如果不想使用 Spring 配置,可以通过 API 的方式 进行调用。
dubbo分布式服务需要三个角色:服务提供者,服务消费者,注册中心
实际开发中我们一般都会使用阿里重新封装后的dubbo框架,使用zookeeper作为服务的注册中心。开发只需要3步操作,1、引入dubbo框架的jar包;2、在配置中添加Dubbo 的配置即可;3、将服务注册到zk上(消费者是从zk上读取服务)。
dubbo工作原理图
一、首先我们来开发一个服务提供者
我们先来创建一个maven多模块项目mailServer:在工作空间中创建一个mailServer文件夹,文件夹中创建一个用来构建多模块项目的pom.xml
<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>dubbo.demo</groupId> <artifactId>mailServer</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>mailService</module> <module>xb-dubbo-parent</module> <module>mail.provider</module> </modules> </project>
然后我们创建一个dubbo-parent,专门用来引入dubbo的包,项目中也只有一个pom.xml文件
<?xml version="1.0" encoding="UTF-8"?> <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>dubbo.demo</groupId> <artifactId>dubbo-parent</artifactId> <version>0.1</version> <packaging>pom</packaging> <properties> </properties> <dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <scope>compile</scope> <version>2.5.3</version> <!-- 排除dubbo包中引入的spring jar包 --> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> </exclusion> </exclusions> </dependency> <!-- 连接zk的包 --> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.7</version> </dependency> </dependencies> <build> </build> </project>
接下来创建两个maven项目mailService和mail.provider
右键 ->new -> maven project
将两个项目在工作空间中移动到mailServer下,删除sts中的所以项目从新导入maven项目
完成后
现在来介绍mailService和mail.provider两个项目:
1)、mailService是一个接口jar包,用来定义对外提供的接口。在生产环境中,我们要将这个接口模块单独打包成jar,作为我们服务的API提供给服务调用者。(如果公司有自己的私服,我们要用deploy命令将他发布到私服上)
2)、mail.provider将会一一实现mailService定义的接口,为调用者提供实际的业务服务。
在这个项目里,我们就要引入dubbo的包、实现具体的业务操作、使用spring配置装配dubbo服务,部署应用(启动应用后,dubbo会自动连接我们配置的注册中心,注册自己的信息到zk上)。
pom.xml
<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.dubbo.demo</groupId> <artifactId>mail.provider</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- 配置变量定义 start --> <properties> <!-- 参数配置文件路径 --> <java.version>1.6</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-version>3.2.3.RELEASE</spring-version> </properties> <!-- 定义变量 end --> <dependencies> <!-- 添加dubbo依赖 --> <dependency> <groupId>dubbo.demo</groupId> <artifactId>dubbo-parent</artifactId> <version>0.1</version> <type>pom</type> </dependency> <!-- 添加本服务对外的接口依赖 --> <dependency> <groupId>com.dubbo.demo</groupId> <artifactId>mailService</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!-- spring 依赖 start --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring-version}</version> </dependency> <!-- 邮件功能start --> <!-- https://mvnrepository.com/artifact/javax.mail/mail --> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4.7</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-email --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-email</artifactId> <version>1.4</version> </dependency> <!-- https://mvnrepository.com/artifact/javax.activation/activation --> <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> <version>1.1.1</version> </dependency> <!-- 邮件功能end --> </dependencies> </project>
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"> <!-- 提供方应用信息,用于计算依赖关系 --> <dubbo:application name="mailService-app" /> <!-- 使用multicast广播注册中心暴露服务地址 --> <!-- 用dubbo协议在20880端口暴露服务 --> <!-- <dubbo:protocol name="dubbo" port="20880" /> --> <dubbo:registry protocol="zookeeper" address="zookeeper://127.0.0.1:2181" client="zkclient" /> <!-- expose this service through dubbo protocol, through port 20880 --> <dubbo:protocol name="dubbo" port="20880" /> <!-- 声明需要暴露的服务接口 --> <dubbo:service interface="com.dubbo.demo.mail.service.MailService" ref="mailService" /> </beans>
创建一个类,implements邮件服务接口mailService.jar包定义的接口,实际的邮件开发功能的实现自己完成
最后一个任务,就是在程序中执行一个服务启动的入口:
package com.dubbo.demo.provider; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Provider { public static void main(String[] args) throws Exception { // 启动spring容器,加载MailServiceImpl服务类 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath*:spring-*.xml"); context.getApplicationListeners(); // 用于保证主线程始终保持运行状态,我们的服务一直提供服务 System.in.read(); // 按任意键退出 } }
二、接下来我们来开发一个消费者
原有程序基础上添加3步:
1、引入dubbo包和服务的对外接口mailService包,在原有的pom中加入依赖
<!-- 添加dubbo依赖 --> <dependency> <groupId>dubbo.demo</groupId> <artifactId>dubbo-parent</artifactId> <version>0.1</version> <type>pom</type> </dependency> <!-- 添加邮件服务对外的接口依赖 --> <dependency> <groupId>com.dubbo.demo</groupId> <artifactId>mailService</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
2、添加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"> <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 --> <dubbo:application name="consumer-of-mailService-app" /> <!-- 使用multicast广播注册中心暴露发现服务地址 --> <dubbo:registry protocol="zookeeper" address="zookeeper://127.0.0.1:2181" client="zkclient" /> <!-- 生成远程服务代理,可以和本地bean一样使用demoService --> <dubbo:reference id="mailService" interface="com.dubbo.demo.mail.service.MailService" /> </beans>
3、调用接口,启动程序测试
public class Consumer { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath*:spring-*.xml"); context.getApplicationListeners(); Mail mail = new Mail(); mail.setReceiver("aa@163.com"); // 接收人 mail.setSubject("测试dubbo邮件"); mail.setMessage("测试dubbo邮件"); MailService mailService = (MailService) context.getBean("mailService"); // 获取远程服务代理 boolean hello = mailService.send(mail); // 执行远程方法 System.out.println(hello); // 显示调用结果 } }
这里我们只是写了个测试demo测试,其实duboo配置中的"id=mailService"已经被创建成一个spring的bean了,可以用注解或者配置文件注入或java代码等任意一种获得bean的方式获得。
三、最后我们来搭建一个zk注册中心(这个公司一般都有自己的运维人员搭建好,不用开发者自己搭建)
下载
http://www.apache.org/dyn/closer.cgi/zookeeper/
解压
D:\Java\soft\zookeeper-3.4.6
伪集群
1、在 \zookeeper-3.4.6\conf\ 新建三个配置文件
zoo1.cfg
tickTime=2000 initLimit=10 syncLimit=5 dataDir=D:\\Java\\soft\\zookeeper-3.4.6\\data\\1 dataLogDir=D:\\Java\\soft\\zookeeper-3.4.6\\log\\1 clientPort=2181 server.1=127.0.0.1:2887:3887 server.2=127.0.0.1:2888:3888 server.3=127.0.0.1:2889:3889
zoo2.cfg
tickTime=2000 initLimit=10 syncLimit=5 dataDir=D:\\Java\\soft\\zookeeper-3.4.6\\data\\2 dataLogDir=D:\\Java\\soft\\zookeeper-3.4.6\\log\\2 clientPort=2182 server.1=127.0.0.1:2887:3887 server.2=127.0.0.1:2888:3888 server.3=127.0.0.1:2889:3889
zoo3.cfg
tickTime=2000 initLimit=10 syncLimit=5 dataDir=D:\\Java\\soft\\zookeeper-3.4.6\\data\\3 dataLogDir=D:\\Java\\soft\\zookeeper-3.4.6\\log\\3 clientPort=2183 server.1=127.0.0.1:2887:3887 server.2=127.0.0.1:2888:3888 server.3=127.0.0.1:2889:3889
三个cfg文件的区别:clientPost、dataDir、dataLogDir不同
2、在 \zookeeper-3.4.6\bin\ 新建三个server
zkServer1.cmd
setlocal call "%~dp0zkEnv.cmd" set ZOOMAIN=org.apache.zookeeper.server.quorum.QuorumPeerMain set ZOOCFG=..\conf\zoo1.cfg echo on java "-Dzookeeper.log.dir=%ZOO_LOG_DIR%" "-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%" -cp "%CLASSPATH%" %ZOOMAIN% "%ZOOCFG%" %* endlocal
zkServer2.cmd
setlocal call "%~dp0zkEnv.cmd" set ZOOMAIN=org.apache.zookeeper.server.quorum.QuorumPeerMain set ZOOCFG=..\conf\zoo2.cfg echo on java "-Dzookeeper.log.dir=%ZOO_LOG_DIR%" "-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%" -cp "%CLASSPATH%" %ZOOMAIN% "%ZOOCFG%" %* endlocal
zkServer3.cmd
setlocal call "%~dp0zkEnv.cmd" set ZOOMAIN=org.apache.zookeeper.server.quorum.QuorumPeerMain set ZOOCFG=..\conf\zoo3.cfg echo on java "-Dzookeeper.log.dir=%ZOO_LOG_DIR%" "-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%" -cp "%CLASSPATH%" %ZOOMAIN% "%ZOOCFG%" %* endlocal
三个server文件的区别:添加set ZOOCFG,三个cmd文件对应各自的cfg文件。
3、添加data和log文件夹
D:\Java\soft\zookeeper-3.4.6 下新建data文件夹
在data下创建1 2 3文件夹
D:\Java\soft\zookeeper-3.4.6 下新建log文件夹
在log下创建1 2 3文件夹
4、创建myid
分别在data\1,data\2,data\3下创建文件 myid,去掉后缀名,并分别添加内容 1、2、3
5、启动Server
启动三个server文件后,用jps查看,会看到三个启动的java主进程。
注:
单机zk bin启动
zookeeper 伪集群(3个zk server)
bin下的zkService1.bat zkService2.bat zkService3.bat 依次启动