一、架构
节点角色说明:
- Provider: 暴露服务的服务提供方
- Consumer: 调用远程服务的服务消费方
- Registry: 服务注册与发现的注册中心
- Monitor: 统计服务的调用次数和调用时间的监控中心
- Container: 服务运行容器
调用关系说明:
- 0. 服务容器负责启动,加载,运行服务提供者
- 1. 服务提供者在启动时,向注册中心注册自己提供的服务
- 2. 服务消费者在启动时,向注册中心订阅自己所需的服务
- 3.注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
- 4.服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用
- 5.服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
说明:
- 注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外
- 注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者
- 注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表
- 注册中心和监控中心都是可选的,服务消费者可以直连服务提供者
用法示例:
首先,定义服务接口,该接口需单独打包,在服务方和消费方共享,通常将其称为api层。
1 package com.patty.dubbo.api.service; 2 3 import com.patty.dubbo.api.domain.UserVo; 4 5 import java.util.List; 6 7 /** 8 * Version: 3.0 9 * Author: pattywgm 10 * Time: 17/5/23 下午5:25 11 * Desc: 用户服务公共接口 12 */ 13 14 public interface UserService { 15 // 查询所有用户 16 public List<UserVo> findAllUsers(); 17 18 // 根据id获取指定用户 19 public UserVo findUserById(String id); 20 }
然后,在服务提供方实现UserService接口,如下:
@Service("userService") public class UserServiceImpl implements UserService { @Autowired private UserBaseService userBaseService; public UserServiceImpl(){ } @Override public List<UserVo> findAllUsers() {
// 去数据库查询所有用户 return userBaseService.findAllUsers(); } @Override public UserVo findUserById(String id) {
// 去数据库查询指定ID的用户 return userBaseService.findUserById(id); } }
UserBaseService是用户查询逻辑的的具体实现,涉及跟数据库,缓存的交互。
接下来,服务提供方要暴露自己的服务给消费者,我们采用springboot配置的方式实现。
<?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="${dubbo.application.name}"/> <!-- 注册中心暴露服务地址 --> <dubbo:registry protocol="${dubbo.registry.protocol}" address="${dubbo.registry.address}"/> <!-- 暴露服务 --> <dubbo:protocol name="${dubbo.protocol.name}" port="${dubbo.protocol.port}"/> <dubbo:service ref="userService" interface="com.patty.dubbo.api.service.UserService"/> </beans>
dubbo.properties文件
#应用名称 dubbo.application.name=dubbo-demo-provider #注册中心协议类型 dubbo.registry.protocol=zookeeper #注册中心地址 dubbo.registry.address=127.0.0.1:2181 #暴露服务方式,采用dubbo协议 dubbo.protocol.name=dubbo #暴露服务端口 dubbo.protocol.port=20880
启动provider,加载配置
@SpringBootApplication @EntityScan("com.patty.dubbo.provider.model") @MapperScan("com.patty.dubbo.provider.dao") public class ProviderServer { public static void main(String[] args) throws IOException{ SpringApplication.run(ProviderServer.class, args); System.in.read(); // 为保证服务一直开着,利用输入流的阻塞来模拟 } }
在消费方通过spring配置调用远程UserService服务,完成消费方的业务逻辑。
<?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="${dubbo.application.name}"/> <!-- 注册中心暴露服务地址 --> <dubbo:registry protocol="${dubbo.registry.protocol}" address="${dubbo.registry.address}" check="false"/> <dubbo:reference id="userService" interface="com.patty.dubbo.api.service.UserService" timeout="10000" retries="3"/> </beans>
// 实现消费端的远程RPC调用
@RestController @RequestMapping("/users") public class UserController { @Resource private UserService userService; @RequestMapping(value = "/all", method = RequestMethod.GET) @ResponseBody public List<UserVo> getAllUsers() { return userService.findAllUsers(); } @RequestMapping(value = "/{userId}",method = RequestMethod.GET) @ResponseBody public UserVo getUser(@PathVariable("userId") String userId) { return userService.findUserById(userId); } }
// 启动消费方服务,加载spring配置,获取远程服务地址列表,供Controller中的业务逻辑调用
@SpringBootApplication public class ConsumerServer { public static void main(String[] args) { SpringApplication.run(ConsumerServer.class, args); } }