提供一个简单的例子:完成下订单,减库存的功能
一、提供服务暴漏的接口,代码如下:
package com.rm.dubbo.service.api;import com.rm.dubbo.service.pojo.Orders;public interface OrdersService {/*** @Description: 根据订单id查询订单*/public Orders getOrder(String orderId);/*** @Description: 下订单*/public boolean createOrder(String itemId);}
用的Mybatis的逆向工程,所以这里生成Orders类和Oreders的条件的类,和对应的mapper.xml的文件,工程如下:
有一个这个api是需要给对应的实现类来引用的。而且在分布式中式服务化的,所以把订单服务放一个子模块,工程的结构如下:
二、加入相应的依赖:
①、由于dubbo2.5.3是阿里维护的最后的一个版本,用的人是最多的。dubbo启动的时候是依赖spring的版本的,dubbo的默认的版本是2.5.6的版本是非常的低的,所以要排除掉。
②、order-service是依赖order-api的,所以也要把order-api的版本控制给引入order-service中。
<dependencies><dependency><groupId>com.rm.dubbo</groupId><artifactId>rm-order-api</artifactId></dependency><!-- Mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId></dependency><dependency><groupId>com.github.miemiedev</groupId><artifactId>mybatis-paginator</artifactId></dependency><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId></dependency><!-- MySql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- 连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId></dependency><!-- Spring --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId></dependency><!-- 引入dubbo --><dependency><groupId>com.alibaba</groupId><artifactId>dubbo</artifactId><exclusions><exclusion><artifactId>spring</artifactId><groupId>org.springframework</groupId></exclusion></exclusions></dependency><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId></dependency><dependency><groupId>com.github.sgroschupf</groupId><artifactId>zkclient</artifactId></dependency><!-- zk 客户端依赖 --><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency></dependencies>
写对应的实现类,代码如下:
package com.rm.dubbo.service.impl;import com.rm.dubbo.mapper.OrdersMapper;import com.rm.dubbo.service.api.OrdersService;import com.rm.dubbo.service.pojo.Orders;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.UUID;@Service("ordersService")public class OrdersServiceImpl implements OrdersService {final static Logger log = LoggerFactory.getLogger(OrdersServiceImpl.class);@Autowiredprivate OrdersMapper ordersMapper;@Overridepublic Orders getOrder(String orderId) {return ordersMapper.selectByPrimaryKey(orderId);}@Overridepublic boolean createOrder(String itemId) {// 创建订单String oid = UUID.randomUUID().toString().replaceAll("-", "");Orders o = new Orders();o.setId(oid);o.setOrderNum(oid);o.setItemId(itemId);ordersMapper.insert(o);log.info("订单创建成功");return true;}}
三、由于需要把这个服务的接口注册到zk上,参考dubbo的官网,需要一个关于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.xsdhttp://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"><!-- 服务提供者的名称,唯一标识 --><dubbo:application name="order-provider"/><!-- 注册中心 --><dubbo:registry address="zookeeper://127.0.0.1:2181"/><!-- 指定暴露的服务端,默认的协议是dubbo--><dubbo:protocol name="dubbo" port="20881"/><!-- 定义暴露的服务接口,ref指的是对应的实现类 --><dubbo:service interface="com.rm.dubbo.service.api.OrdersService" ref="ordersService"/></beans>
对应整个项目的结构如下:
然后测试下,启动这个服务,然后启动zk,控制台的信息打印如下:
其中注册打印的信息如下:dubbo默认的协议的是dubbo,用的是dubbo的统一的标准。
Register: dubbo://169.254.18.74:20881/com.rm.dubbo.service.api.OrdersService?anyhost=true&application=order-provider&dubbo=2.5.3&interface=com.rm.dubbo.service.api.OrdersService&methods=createOrder,getOrder&pid=14544&revision=1.0-SNAPSHOT&side=provider×tamp=1580444734532, dubbo version: 2.5.3, current host: 127.0.0.1
20881:是dubbo的端口号,169.254.18.74:本机的ip地址。com.rm.dubbo.service.api.OrderService:暴漏出接口的全路径。anyhost:true,代表任何机器都可以访问,没有权限。application=orderprovider:代表这个服务定义的名称。dubbo=2.5.3,dubbo的版本用的是2.5.3的版本。interface=com.rm.dubbo.service.api.OrderService&methods=createOrder,getOrder:这个告诉哪一个接口里的哪一个方法。pid:是当前进程的id。revision=1.0-SNAPSHOT:当前项目的版本。sid=provider代表是一种提供服务的角色。timestamp:毫秒值。后面的是dubbo的版本和主机。
然后查看下zk上的注册信息:
configurations节点:配置会话的 providers:配置服务提供者的,数组的原因是一个接口当中会有很多的实例,这样就可以做成负载均衡。 而在providers节点中的内容和控制台打印的内容是一样的,只不过是做了转义。这就是注册生成协议的信息。
同样也提供商品服务,工程结构如下:
提供暴漏出接口中的方法:
package com.rm.dubbo.service.api;import com.rm.dubbo.service.pojo.Items;public interface ItemsService {/*** @Description: 根据商品id获取商品*/public Items getItem(String itemId);/*** @Description: 查询商品库存*/public int getItemCounts(String itemId);/*** @Description: 购买商品成功后减少库存*/public void displayReduceCounts(String itemId, int buyCounts);}
同样也需要把这个服务注册到zk上。
然后提供相应的消费端,工程结构如下:
在接口BuyService接口中,提供相应的买商品的方法,代码如下:
package com.rm.web.service;public interface BuyService {/*** @Description: 购买商品*/public void doBuyItem(String itemId);public boolean displayBuy(String itemId);}
对应的实现类如下:
package com.rm.web.service.impl;import com.rm.dubbo.service.api.ItemsService;import com.rm.dubbo.service.api.OrdersService;import com.rm.web.service.BuyService;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Service;import javax.annotation.Resource;@Service("buyService")public class BuyServiceImpl implements BuyService {final static Logger log = LoggerFactory.getLogger(BuyServiceImpl.class);@Resourceprivate ItemsService itemService;@Resourceprivate OrdersService ordersService;@Overridepublic void doBuyItem(String itemId) {// 减少库存itemService.displayReduceCounts(itemId, 1);// 创建订单ordersService.createOrder(itemId);}@Overridepublic boolean displayBuy(String itemId) {int buyCounts = 5;// 1. 判断库存int stockCounts = itemService.getItemCounts(itemId);if (stockCounts < buyCounts) {log.info("库存剩余{}件,用户需求量{}件,库存不足,订单创建失败...",stockCounts, buyCounts);return false;}// 2. 创建订单boolean isOrderCreated = ordersService.createOrder(itemId);// 3. 创建订单成功后,扣除库存if (isOrderCreated) {log.info("订单创建成功...");itemService.displayReduceCounts(itemId, buyCounts);} else {log.info("订单创建失败...");return false;}return true;}}
然后消费端也需要把自己注册到zk上,也需要订阅上面的两个服务。所以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.xsdhttp://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"><dubbo:application name="web-consumer"/><!-- 注册中心 --><dubbo:registry address="zookeeper://127.0.0.1:2181"/><!-- 引用暴露的服务ordersService和itemService如果和属性的名称相同,则按照名称来装配,否则按照类型装配。interface的值指向接口的全路径,这样做之后把接口的实现类完全放到spring容器中去管理了--><dubbo:reference id="ordersService" interface="com.rm.dubbo.service.api.OrdersService"/><dubbo:reference id="itemService" interface="com.rm.dubbo.service.api.ItemsService" /></beans>
然后启动消费端:返回的结果是200,代表购买成功。
由于是分布式的项目,数据库做成垂直的拆分。所以分成两个数据库。
这时刷新下数据库。
上面的过程就是dubbo的通过在tomcat容器中启动。一个简单的入门。晚上分享如何去写一个简单的rpc框架。