2018年2月15日,阿里巴巴的dubbo进入了Apache孵化器,社区的加入,希望dubbo能变得更好…
Registry:注册中心,相当于房产中介,服务提供者和使用者都需要在这里注册/使用服务,
我使用 zookeeper 实现。
Monitor:监控中心,相当于房产局,它可以统计服务提供者和服务使用者的一些信息,及他们之间的关系,
我使用 dubbo admin 实现。
Provider:服务提供者,相当于房东,提供服务。
Consumer:服务消费者,想当于租户,使用服务。
通俗的解释下 dubbo 的整个流程,将服务比喻成房子:
start:dubbo 一启动,房东想好自己准备要租出去的房子
register:房东将房子拿到房产中介那边进行登记,并留下自己的联系方式
subscribe:租户告诉房产中介自己想租一个什么样的房子
notify:房产中介回复给租户符合条件的房子的房东的联系方式
invoke:租户拿着联系方式去找房东租房子
count:房产局全程监控着房东和租户之间的交易
start、register、subscribe 在 dubbo 服务一启动就完成了
notify、count 是异步执行的
invoke 是同步执行的
四、配置项目
<properties>
<dubbo.version>2.6.1</dubbo.version>
<zookeeper.version>3.5.2-alpha</zookeeper.version>
<curator.version>4.0.1</curator.version>
</properties>
<!-- dubbo包 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<!-- 排除dubbo自带的spring和netty,使用项目的,如果本身项目没有,无需排除 -->
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>org.jboss.netty</groupId>
<artifactId>netty</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- zookeeper包 -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<type>pom</type>
</dependency>
<!-- curator(zookeeper的客户端)包 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
</dependency>
还需要在相关配置文件加上 dubbo 的 bean 的头部约束,将下面的添加到 bean 头部即可:
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
4.1 服务提供方代码
import org.springframework.stereotype.Service;
@Service
public class TbItemServiceImpl extends ServiceImpl<TbItemMapper, TbItem> implements TbItemService {
}
需要修改 spring 关于 service 的配置文件,加入 dubbo 的配置信息:
<?xml version="1.0" encoding="UTF-8"?>
<beanshttp://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
>
<!-- 扫描service层注解 -->
<context:component-scan base-package="jit.wxs.service"/>
<!-- dubbo发布服务 -->
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="e3-manager" />
<!-- 配置zookeeper的地址,集群地址用逗号隔开 -->
<dubbo:registry protocol="zookeeper" address="192.168.30.145:2181" />
<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880" />
<!-- 声明需要暴露的服务接口
ref:为注入的对应接口的bean
timneout:超时时间,单位ms,开发模式可以设长一点方便debug
-->
<dubbo:service interface="jit.wxs.service.TbItemService"
ref="tbItemServiceImpl" timeout="600000"/>
</beans>
dubbo:application:提供方的应用名
dubbo:registry:注册中心的类型和地址
dubbo:protocol:这个服务要暴露在哪个端口上(使用方根据这个端口使用服务)
dubbo:service:设置暴露的服务的接口,ref 为该接口的 bean,timeout 为超时时间
4.2 服务使用方代码
服务使用方,我使用 Spring MVC 来实现,修改 Spring MVC 的配置文件,加入 dubbo 的配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd"
>
<!-- 扫描组件 -->
<context:component-scan base-package="jit.wxs.web"/>
<!-- 注解驱动 -->
<mvc:annotation-driven />
<!-- 全局异常类 -->
<!--<bean class="cn.edu.jit.exception.GlobalExceptionResolver"/>-->
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 引用dubbo服务 -->
<!-- 使用方应用信息,用于计算依赖关系 -->
<dubbo:application name="e3-manager-web"/>
<!-- 指定zookeeper的地址,集群用逗号分隔 -->
<dubbo:registry protocol="zookeeper" address="192.168.30.145:2181"/>
<!-- 申明要访问的接口,并创建代理对象,注入bean,名为id的值 -->
<dubbo:reference interface="jit.wxs.service.TbItemService" id="tbItemService" />
</beans>
dubbo:application: 使用方的应用名
dubbo:registry:注册中心的类型和地址
dubbo:reference:要使用的服务的接口,并将返回的注入 bean,名称为id设的值
如果配置没有问题的话,现在使用方已经能够使用提供方提供的服务了,直接将 tbItemService
注入进来即可:
@RestController
@RequestMapping("/items")
public class TbItemController {
@Autowired
private TbItemService tbItemService;
@GetMapping("/{id}")
public TbItem getItemById(@PathVariable Long id) {
TbItem item = null;
if(id != null) {
item = tbItemService.selectById(id);
}
return item;
}
}
dubbo和zookeeper项目中使用
服务的提供者将服务注册到注册中心,服务的消费者从注册中心获取服务,monitor监控服务的调用。
框架无非就是配置文件+java代码,所以dubbo也同理:
(1)首先看下B服务的提供者的配置文件和代码:
搭建b系统:
建立一个maven的war工程,导入依赖
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.3.3</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.5.3</version>
<exclusions>
<exclusion>
<!-- 排除传递spring依赖 -->
<artifactId>spring</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
第二步:创建user对象:注意这里一定要实现序列化,并获取序列化的序号:
// 使用dubbo要求传输的对象必须实现序列化接口
public class User implements java.io.Serializable
创建服务接口和服务接口的实现类:
接口为了暴露服务的:
public interface UserService {
/**
* 查询所有的用户数据
*
* @return
*/
public List<User> queryAll();
}
5.3.6. 创建UserServiceImpl实现类
public class UserServiceImpl implements UserService {
/**
* 实现查询,这里做模拟实现,不做具体的数据库查询
*/
public List<User> queryAll() {
List<User> list = new ArrayList<User>();
for (int i = 0; i < 10; i++) {
User user = new User();
user.setAge(10 + i);
user.setId(Long.valueOf(i + 1));
user.setPassword("123456");
user.setUsername("username_" + i);
list.add(user);
}
return list;
}
}
下面就是dubbo的服务提供者的配置文件了:
实际项目中,相当于服务的提供者的第一步:编写配置文件
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd"
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="dubbo-b-server" />
<!-- 这里使用的注册中心是zookeeper -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" client="zkclient"/>
<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880" />
<!-- 将该接口暴露到dubbo中 -->
<dubbo:service interface="cn.itcast.service.UserService" ref="userServiceImpl" />
<!-- 将具体的实现类加入到Spring容器中 -->
<bean id="userServiceImpl" class="cn.dubbo.service.impl.UserServiceImpl" /><br>
这里spring与dubbo进行了无缝整合,所以这里进行了spring与dubbo的整合:
第二步:读取配置文件
我们需要在web.xml中将配置文件引入:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dubbo/dubbo-*.xml</param-value>
</context-param>
<!--Spring的ApplicationContext 载入 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
第三步:配置服务消费者:
这里我们建立a的系统:
建立一个maven的jar工程:
导入依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.5.3</version>
<exclusions>
<exclusion>
<!-- 排除传递spring依赖 -->
<artifactId>spring</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.3.3</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
</dependencies>
从b系统拷贝:
1.1.1. 从b系统中拷贝User对象、UserService接口道a系统
服务的消费者配置:
dubbo-consumer.xml
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="dubbo-a-consumer" />
<!-- 这里使用的注册中心是zookeeper -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" client="zkclient"/>
<!-- 从注册中心中查找服务 -->
<dubbo:reference id="userService" interface="cn.itcast.dubbo.service.UserService"/>
(1)导入dubbo、zookeeper依赖
(2)在服务提供者端,编写服务接口,服务接口的实现类,编写配置文件
(3)修改web.xml读取配置文件
(4)在服务消费者,即客户端,调用服务接口,调用服务实现类,编写配置文件
dubbo与zookeeper的关系
Dubbo建议使用Zookeeper作为服务的注册中心。
1. Zookeeper的作用:
zookeeper用来注册服务和进行负载均衡,哪一个服务由哪一个机器来提供必需让调用者知道,简单来说
就是ip地址和服务名称的对应关系。 zookeeper通过心跳机制可以检测挂掉的机器并将挂掉机器的ip和服务
对应关系从列表中删除。至于支持高并发,简单来说就是横向扩展,在不更改代码 的情况通过添加机器来
提高运算能力。通过添加新的机器向zookeeper注册服务,服务的提供者多了能服务的客户就多了。
2. dubbo:
是管理中间层的工具,在业务层到数据仓库间有非常多服务的接入和服务提供者需要调度,dubbo提供一个
框架解决这个问题。
这个框架中要完成调度必须要有一个分布式的注册中心,储存所有服务的元数据,你可以用zk,也可以用别的,
只是大家都用zk。
3. zookeeper和dubbo的关系:
Dubbo的将注册中心进行抽象,是得它可以外接不同的存储媒介给注册中心提供服务,
有ZooKeeper,Memcached,Redis等。
引入了ZooKeeper作为存储媒介,也就把ZooKeeper的特性引进来。首先是负载均衡,单注册中心的承载能力
是有限的,在流量达到一定程度的时 候就需要分流,负载均衡就是为了分流而存在的,一个ZooKeeper群配合
相应的Web应用就可以很容易达到负载均衡;资源同步,单单有负载均衡还不 够,节点之间的数据和资源需要
同步,ZooKeeper集群就天然具备有这样的功能;
Dubbo(Dubbo与Zookeeper、SpringMVC整合)
第一步:在Linux上安装Zookeeper
Zookeeper作为Dubbo服务的注册中心,Dubbo原先基于数据库的注册中心,没采用Zookeeper,Zookeeper
一个分布式的服务框架,是树型的目录服务的数据存储,能做到集群管理数据 ,这里能很好的作为Dubbo服务
的注册中心,Dubbo能与Zookeeper做到集群部署,当提供者出现断电等异常停机时,Zookeeper注册中心能
自动删除提供者信息,当提供者重启时,能自动恢复注册数据,以及订阅请求。
(1)下载Zookeeper-3.4.6.tar.gz 地址http://www.apache.org/dist/zookeeper/
(2) 我们放到Linux下的一个文件夹,然后解压:
tar zxvf zookeeper-3.4.6.tar.gz
clientPort:监听客户端连接的端口。
tickTime:基本事件单元,以毫秒为单位。它用来控制心跳和超时,默认情况下最小的会话超时时间为
两倍的 tickTime。
第二步:配置dubbo-admin的管理页面,方便我们管理页面
(1)下载dubbo-admin-2.4.1.war包,在Linux的tomcat部署,先把dubbo-admin-2.4.1放在
tomcat的webapps/ROOT下,然后进行解压:
jar -xvf dubbo-admin-2.4.1.war
(2)然后到webapps/ROOT/WEB-INF下,有一个dubbo.properties文件,里面指向Zookeeper ,使用的
是
Zookeeper 的注册中心,如图所示:
(3)然后启动tomcat服务,用户名和密码:root,并访问服务,显示登陆页面,说明dubbo-admin
部署成功,
如图所示:
第三步:SpringMVC与Dubbo的整合,这边使用的Maven的管理项目
第一:我们先开发服务注册的,就是提供服务,项目结构如图所示:
(1)test-maven-api项目加入了一个服务接口,代码如下:
public interface TestRegistryService {
public String hello(String name);
}
(2)test-maven-console在pom.xml加入Dubbo和Zookeeper的jar包、引用test-maven-api的jar包
(3)test-maven-console实现具体的服务,代码如下:
@Service("testRegistryService")
public class TestRegistryServiceImpl implements TestRegistryService {
public String hello(String name) {
return "hello"+name;
}
}
(4)我们服务以及实现好了,这时要暴露服务,代码如下:
<!-- 提供方应用名称信息,这个相当于起一个名字,我们dubbo管理页面比较清晰是哪个应用
暴露出来的 -->
<dubbo:application name="dubbo_provider"></dubbo:application>
<!-- 使用zookeeper注册中心暴露服务地址 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" check="false"
subscribe="false" register=""></dubbo:registry>
<!-- 要暴露的服务接口 -->
<dubbo:service
interface="cn.test.dubbo.registry.service.TestRegistryService"
ref="testRegistryService" />
dubbo:registry 标签一些属性的说明:
1)register是否向此注册中心注册服务,如果设为false,将只订阅,不注册。
2)check注册中心不存在时,是否报错。
3)subscribe是否向此注册中心订阅服务,如果设为false,将只注册,不订阅。
4)timeout注册中心请求超时时间(毫秒)。
5)address可以Zookeeper集群配置,地址可以多个以逗号隔开等。
dubbo:service标签的一些属性说明:
1)interface服务接口的路径
2)ref引用对应的实现类的Bean的ID
4)register 默认true ,该协议的服务是否注册到注册中心。
(5)启动项目,然后我们在Dubbo管理页面上显示,已经暴露的服务,但显示还没有消费者,因为我们还没
实现消费者服务,如图所示:
第二:我们在开发服务消费者,就是调用服务,我们在新建一个新的消费者项目结构如图所示:
1)test-maven-server-console的pom.xml引入Dubbo和Zookeeper的jar包、test-maven-api的jar包,
因为引入test-maven-api的jar包,我们在项目中调用像在本地调用一样。
(2)test-maven-server-console项目的具体实现,代码如下:
@Controller
public class IndexController {
@Autowired
private TestRegistryService testRegistryService;
@RequestMapping("/hello")
public String index(Model model){
String name=testRegistryService.hello("zz");
System.out.println("xx=="+name);
return "";
}
}
(3)我们要引用的地址,代码如下:
<dubbo:application name="dubbo_consumer"></dubbo:application>
<!-- 使用zookeeper注册中心暴露服务地址 -->
<dubbo:registry address="zookeeper://192.168.74.129:2181" check="false"></dubbo:registry>
<!-- 要引用的服务 -->
<dubbo:reference interface="cn.test.dubbo.registry.service.
TestRegistryService" id="testRegistryService"></dubbo:reference>
说明:
dubbo:reference 的一些属性的说明:
1)interface调用的服务接口
2)check 启动时检查提供者是否存在,true报错,false忽略
3)registry 从指定注册中心注册获取服务列表,在多个注册中心时使用,值为<dubbo:registry>的
id属性,多个注册中心ID用逗号分隔
4)loadbalance 负载均衡策略,可选值:random,roundrobin,leastactive,分别表示:随机,轮循,最少活跃调用
(4)项目启动,Dubbo管理页面,能看到消费者,
(5)然后访问消费者项目,Controller层能像调用本地一样调用服务的具体实现