Dubbo基础专题——第二章(Dubbo工程简单实践)

Posted 皮卡皮卡程序员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo基础专题——第二章(Dubbo工程简单实践)相关的知识,希望对你有一定的参考价值。

前言:刚完成的Spring基础专题本想更新源码的,但是发现分布式非常火,而我喜欢玩这个,所以今年我希望把我的知识可以分享给正在奋斗中的互联网开发人员,以及未来想往架构师上走的道友们我们一起进步,从一个互联网职场小白到一个沪漂湿人,一路让我知道分享是一件多么重要的事情,总之不对的地方,多多指出,我们一起徜徉代码的海洋!
 
我这里做每个章节去说的前提,不是一定很标准的套用一些官方名词,目的是为了让大家可以理解更加清楚,如果形容的不恰当,可以留言出来,万分感激!

1、工程搭建

睡醒了,接着上节的讲,我们还是这个图,要实现下面的三个模块,那么对于新手来说,可能不知道什么是公共接口层,那这我就先不做这一层,我先做两个工程,一个是订单模块作为消费者,一个是用户服务模块作为生产者

实现的业务是,订单服务要查询用户的地址,订单是有用户的地址的!

我这里拿idea演示步骤,顺便讲下多工程是怎么创建的,如果会的人,就快速过一遍就好了~!

先创建一个父类的pom文件,这个pom是管理里面的所有的项目及其子项目的!

接下来

接着

点击finish,然后项目建成了,再点击右键new——module

还是这个老界面

2、创建消费端和生产端

下一步,然后保持默认的

然后finish后,成这样,注意,你要把src删除,删除后是这样

这个时候我们再建gmall-user,是生产者,用户服务模块

重复上面的步骤,我不写了啊,结果项目结构是这样的!(有些细节不用太在意,我们本节的目的是dubbo的基础开发)

 

此时我们创建一个类,叫做UserAddress,在com.chenxin.dubbo.entity下,此类是用户地址类

/**
 * 用户地址
 *
 * @author chenxin
 */
public class UserAddress implements Serializable {

    private Integer id;
    //用户地址
    private String userAddress;
    //用户id
    private String userId;
    //收货人
    private String consignee;
    //电话号码
    private String phoneNum;
    //是否为默认地址    Y-是     N-否
    private String isDefault;

    public UserAddress() {
        super();
        // TODO Auto-generated constructor stub
    }

    public UserAddress(Integer id, String userAddress, String userId, String consignee, String phoneNum,
                       String isDefault) {
        super();
        this.id = id;
        this.userAddress = userAddress;
        this.userId = userId;
        this.consignee = consignee;
        this.phoneNum = phoneNum;
        this.isDefault = isDefault;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserAddress() {
        return userAddress;
    }

    public void setUserAddress(String userAddress) {
        this.userAddress = userAddress;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getConsignee() {
        return consignee;
    }

    public void setConsignee(String consignee) {
        this.consignee = consignee;
    }

    public String getPhoneNum() {
        return phoneNum;
    }

    public void setPhoneNum(String phoneNum) {
        this.phoneNum = phoneNum;
    }

    public String getIsDefault() {
        return isDefault;
    }

    public void setIsDefault(String isDefault) {
        this.isDefault = isDefault;
    }


}

再写个业务类UserService,在com.chenxin.dubbo.service下

/**
 * 用户服务
 * @author chenxin
 *
 */
public interface UserService {
	
	/**
	 * 按照用户id返回所有的收货地址
	 * @param userId
	 * @return
	 */
	public List<UserAddress> getUserAddressList(String userId);

}

实现类com.chenxin.dubbo.service.impl.UserServiceImpl,我这里就不连接数据库不做这么复杂了,简简单单的过下核心的东西!

public class UserServiceImpl implements UserService {

	@Override
	public List<UserAddress> getUserAddressList(String userId) {
		System.out.println("UserServiceImpl.....old...");
		// TODO Auto-generated method stub
		UserAddress address1 = new UserAddress(1, "阿里西溪园区蚂蚁金服大楼", "1", "chenxin", "010-56253825", "Y");
		UserAddress address2 = new UserAddress(2, "阿里西溪园区支付宝大楼", "1", "chenxin2", "010-56253825", "N");
	
		return Arrays.asList(address1,address2);
	}
}

那么服务的提供者我已经写好了,接下来我写服务的调用者,也就是订单服务!

3、编写两个服务业务逻辑

创建工程依旧是maven工程,我这里不重复创建了

我需要一个订单的service业务,进行订单的业务处理

public interface OrderService {

    List<UserAddress> initOrder(String userId);
}

实现类

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private UserService userService;

    @Override
    public List<UserAddress> initOrder(String userId) {
        // TODO Auto-generated method stub
        System.out.println("用户id:" + userId);
        //1、查询用户的收货地址
        List<UserAddress> addressList = userService.getUserAddressList(userId);
        for (UserAddress userAddress : addressList) {
            System.out.println(userAddress.getUserAddress());
        }
        return addressList;
    }
}

但是这个时候在订单服务里,需要用到查询用户的地址,所以就需要有重复的UserAddress类,因为需要注入,所以需要用到UserService,所以你需要在订单服务里,也要写OrderService,你看,代码是不是重复了?

给你看下最后的效果!

所以你知道为什么Dubbo官网建议我们有句话,建议将服务接口、服务模型、服务异常等均放在 API 包中!!!!

所以我们需要多一个项目,这个项目只放:实体类+api接口,因为这些都是重复可以被重复使用的,很有可能其他的服务也要调用UserService这个接口,去调用里面的方法,当然不仅仅是这个用法,后面我再说

此时新建一个项目叫做api-service,其实就是文章开始前的gmall-interface这个项目,因为属于公共接口层,所以我这里就命名为api-service

我们把所有的接口,和实体类都放在里面,pom文件记得要加上这个api-service的依赖,我这里就默认知道你们是懂maven的,不懂的就回去看看maven。

那么这个结构就已经完成了,代码我会贴出来的,到时候你们下下来看看。

那么这个时候,订单服务在A服务器上,用户服务在B服务器上,他们怎么进行通信呢?对,就是RPC,就好像调用本地一样,不会改什么代码。

所以我们要把这两个服务做成可以支持远程调用的

1、引入dubbo的依赖,提供方和调用方都要引入,注意我用的是2.6.x版本后,用的curator依赖,操作Zookeeper,2.6之前的用zkClient依赖,所以根据你项目的来,我这用的是2.6.2版本

        <!-- 引入dubbo -->
        <!-- https://mvnrepository.com/artifact/com.alibaba/dubbo -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.2</version>
        </dependency>
        <!-- 注册中心使用的是zookeeper,引入操作zookeeper的客户端 -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>2.12.0</version>
        </dependency>

2、将服务提供者user注册到注册中心,也就是暴露服务。

怎么暴露呢,官网上有相关说明

所以我这创建一个provider.xml在用户服务的resource下,代码可以从官网贴来后改改

<?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://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd        http://dubbo.apache.org/schema/dubbo        http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!-- 提供方应用信息,用于计算依赖关系 -->
    <dubbo:application name="gmall-user"  />

    <!-- 使用zookeeper注册中心暴露服务地址 -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181" />

    <!-- 用dubbo协议在20880端口暴露服务 -->
    <dubbo:protocol name="dubbo" port="20880" />

    <!-- 声明需要暴露的服务接口 -->
    <dubbo:service interface="com.chenxin.dubbo.service.UserService" ref="userService" />

    <!-- 和本地bean一样实现服务 -->
    <bean id="userService" class="com.chenxin.dubbo.service.impl.UserServiceImpl" />
</beans>

看下标签的意义:我还是贴出来官网的图

所以对于xml的标签意思,对着这个图看看就可以了,应该都是很好理解的。

注意几个点,因为我们当前用的注册中心是zookeeper,所以我这里写的registry是 <dubbo:registry address="zookeeper://127.0.0.1:2181" />

详见:其实官网真的很详细,要学会看官方文档!!!!

那我们到这就完成了暴露过程,我们可以写个main函数试试看是不是真的。

测试下main函数后,因为本地已经启动了dubbo-admin服务,所以我们访问下localhost:7001 看看,因为main函数我写了个read卡着,就可以看到下图的效果,我的UserService已经被暴露在这上面了

有很多初学者会疑惑,这个界面哪来的,这个界面其实是dubbo-admin的端口,zk的端口是2181,所以千万不要认为这个是注册中心的界面啊。zk是一个协议,协议,不是一个控制台的东西,千万记住。

3、服务的消费者,就是order模块,要订阅服务的提供者的接口

同样我在order项目的resource下建立一个consumer.xml

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    
    <dubbo:application name="gmall-order-web"/>
    
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    
    <dubbo:reference id="userService" interface="com.chenxin.dubbo.service.UserService"/>
</beans>

同样标签的意思,服务消费者为什么要也要写registry?因为你要去调用,需要发现注册中心的地方在哪里,不然怎么能发现其他的服务呢。

同样reference是引用的意思,你要引用提供者的什么呢,当然是接口UserService了。

写个消费者的测试类:

public class OrderApplication {
	
	@SuppressWarnings("resource")
	public static void main(String[] args) throws IOException {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("consumer.xml");
		
		OrderService orderService = applicationContext.getBean(OrderService.class);
		
		orderService.initOrder("1");
		System.out.println("调用完成....");
		System.in.read();
	}

}

所以启动后,发现消费者order,也注册在zk中,并且控制台也打印了调用的结果!!

这个时候如果你发现你启动报错no Provider,那把提供者重启下就好了,后面我说原理为什么会这样!

所以到这里我们的服务的调用者和消费者都已经成功注册上Zookeeper并且在dubbo-admin的控制台我们可以看到相关的信息!!

代码地址:

链接:https://pan.baidu.com/s/1XyFOfPDskI9lJbn2fThkvw   提取码:hfui 

到这,我们就通过简单的Spring案例,将两个服务注册到注册中心上,并且实现了服务提供者和服务消费者之间的简单调用关系,模拟了rpc远程调用的过程,实际上,你发现没有,这个远程调用,你只要暂时先理解为,就好比本地调用你的java代码一样,没

有什么其他的变动,我们还是像在一个服务内,该写注入写注入。这就是rpc的特色,当然这是基础的一点点,远不止这些!!

下一节我来整合Springboot后,详细说明Dubbo里面的很多使用,和属性点,敬请期待!!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

以上是关于Dubbo基础专题——第二章(Dubbo工程简单实践)的主要内容,如果未能解决你的问题,请参考以下文章

Dubbo 专题(基础篇):Dubbo 介绍环境搭建与实践

Dubbo 专题(基础篇):Dubbo 介绍环境搭建与实践

Dubbo 专题(基础篇):Dubbo 介绍环境搭建与实践

Dubbo基础专题——第四章(Dubbo整合Nacos分析细节点)

Dubbo基础专题——第三章(Dubbo整合SpringBoot分析细节点)

个人学习分布式专题分布式服务治理之Dubbo框架