应广大的读者要求,也是公司目前需要一些支持,我就自己亲身搭建一个Springboot+nacos+dubbo的框架和项目,并演示dubbo面对一些系统的
业务场合,应该怎么去做支持,文章中我会先贴出代码地址,如果不需要仔细的学习,那么直接下载地址就好了,
如果想跟着学为什么要这么玩,那么请耐心的往下看,我会用很简单的语言,来诠释很多概念和你们在搭建的时候,会遇到的一些问题,这些问题
应该怎么处理,产生的原因是什么,好了废话不多说,开始了!!
1、环境搭建
idea版本,你随便
jdk版本,1.8+以上
首先我新建一个父工程
然后写你的groupId和artifictId,你可以不按照我这么写,如果你对maven熟悉的话
然后选择路径
创建好后,你把src删除掉,结构是这样的
然后再建立几个子工程,我只举一个例子,剩下的自己创建哈!
然后新建还是maven项目
创建一个用户服务
然后finish,src就别给我删了啊。。。
创建user服务对外暴露的api项目,叫做user-provider-api
生产者部分已经创建完了,接着创建消费者,订单服务order-consumer,负责调用生产者user,获取用户信息;
重复上面的步骤,是这样的
好,接下来我们先做依赖关系,我们本章的要求是搭建一个Springboot+nacos+dubbo,
我默认读者是已经了解过这些技术,但是需要一个比较完整的环境;
nacos是阿里的产品,本章我目前只用来做个注册中心,配置中心的用法我后面说
dubbo看我前两章节,写的比较清楚
首先这个依赖管理,我要让springboot-nacos-dubbo这个父类管理依赖,所以我要让项目的父pom继承springboot的parent;
pom
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.9.RELEASE</version> <relativePath/> </parent>
这样就表明我这个项目,已经从maven迈进springboot的第一步。
然后这个父pom要管理依赖关系
<properties>
<java.version>1.8</java.version>
<spring-cloud-alibaba.version>2.1.1.RELEASE</spring-cloud-alibaba.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
<dubbo.version>2.7.3</dubbo.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
截图说明下,既然是nacos,就从属于Alibaba微服务系列,需要建立个版本约定进来,子项目你用不用那另说;
既然springboot要整合dubbo,就要有整合的场景驱动器dubbo-spring-boot-starter
那么springcloud依赖为什么要引进来呢,其实这个我也说不好,官网的demo案例就这么干的:
看依赖截图:
所以对于user-provider来说,pom是这样的:
<dependencies>
<!-- springboot web相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<!--nacos注册中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--nacos配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
2、开始编码
用户服务要拿用户信息,我们在user-provider-api中写实体和接口,原因我上一节已经说明,因为在实体,接口,都会被其他服务所引用;
所以我们要编写用户实体,用户接口类
public class User {
private Integer id;
private String username;
public User(Integer id, String username) {
this.id = id;
this.username = username;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
UserService接口
public interface UserService {
User getUserInfo(Integer id);
}
整体的截图是这样的:
接口实体都有了,那么可以在服务中暴露接口+业务逻辑了,前提user-provider的依赖要把user-provider-api引入进来,记得要把api install到本地,不然找不到!
那么这个时候,是不是少了一个主启动类?不然你怎么启动你的user-provider?
注意你的目录级别,主启动类建议以这样的方式走,知道Springboot的就知道刚创建出来的项目结构就是这样的;@EnableDubbo这个注解是开启注解配置dubbo;
然后我们要配置application.yml和bootstrap.yml,这两者区别是:
bootstrap 里面的属性在springboot项目启动的时候,会优先加载,对于nacos来说,建议配置在bootstrap中
在resource下新建两个文件,application.yml和bootstrap.yml
bootstrap.yml
spring:
cloud:
nacos:
config:
enabled: false
server-addr: 127.0.0.1:8848
discovery:
server-addr: 127.0.0.1:8848
application.yml
server:
port: 8081
spring:
application:
name: user-provider
dubbo:
consumer:
check: false
application:
name: ${spring.application.name}
protocol:
port: 20881
name: dubbo
registry:
address: nacos://127.0.0.1:8848
这些属性的意思我后面收尾介绍,先搭建起来
我们用nacos是本地的,所以可以下载版本下来,windows版本地址是:https://github.com/alibaba/nacos/releases/download/1.3.2/nacos-server-1.3.2.zip
然后本地解压后启动nacos,进入nacos的bin目录,以单机模式启动;
默认是8848端口,输入地址:http://localhost:8848/nacos
登陆名和密码都是nacos
这样nacos就启动成功了!!!
于是我们启动user-provider服务
在nacos注册中心上会有两行,第一行就是你的服务要被nacos发现,注册上你服务的信息,第二行是provider:com....,很明显,是你暴露的服务名,因为你的UserServiceImpl加了@Service注解,那么dubbo就会把你的服务暴露在注册中心!!
那么提供者我们已经做好了,该消费端order-service了,其实步骤和上面差不多,我主要写些不同之处
api中
service:
同样我在order服务中我要调用user服务,需要写个controller,里面要远程调用UserService接口,所以别忘记在order-consumer这个服务中pom要引入user-provider-api的依赖!!!这些我其实都不想说了,但是为了初学者可以看懂,我也拼了。。。
紧接着你肯定要把你暴露接口的实现也要写下
差个主启动类,注意层级关系
同样bootstrap和application复制一份进来,但是记得有些地方要改改
bootstrap.yml不变,和生产者一样;
application.yml,注意端口变了,user服务的端口是8081,order是8080,还有服务名也要改变,还有就是dubbo协议发起的端口,user是20881,order是20880,一个服务一个协议端口,这点要记清楚!!不然端口冲突
server:
port: 8080
spring:
application:
name: order-consumer
dubbo:
consumer:
check: false
application:
name: ${spring.application.name}
protocol:
port: 20880
name: dubbo
registry:
address: nacos://127.0.0.1:8848
然后我们要启动消费者,启动成功;
看下nacos,多出来两个,下面一个是消费者服务,上面一个是因为加了远程调用的注解@Reference,产生了consumer:com....,会告诉注册中心,我消费者服务也要去 注册中心上找提供者。
有人会有疑惑,我作为消费者,我只需要从注册中心找就可以了,为啥要把自己注册到注册中心呢?应该是有这个疑问的吧?
当然不是,如果作为消费者,你的服务不让注册中心知道,你连门都进不去,你怎么去要这栋大楼的花名册?进来至少要登记你的信息,后面你消费者存不存在了,注册中心也需要感知,怎么感知呢,所以你也要注册上注册中心。
所以我们调用接口地址:localhost:8080/getOrder
哦豁,报错了,看我标记,dubbo中传输数据,需要序列化和反序列化,所以你所有的实体都应该实现Serializable接口,这里记得改下!!!!
当把所有的实体都加上序列化后,
两个服务都重启后,调用结果是:
控制台已经打印,说明已经调用成功!!!
那么简单的消费者和生产者我就演示到这,我接下来说下配置文件的事情!!
来看配置文件,先看bootstrap
spring.cloud.nacos.config.enable: false 表示是否开启配置中心?因为nacos既可以用做注册中心,也可以作为配置中心;这里我们只用来做注册中心,后面的server-addr是表示配置中心的地址,关闭不开启,写不写都可以
所以重点关注spring.cloud.nacos.discovery 表示服务注册发现,也就是注册中心地址,因为默认的enable属性是true,默认开启注册中心,所以写个地址就好
还是那句话,我们建议nacos注册中心的服务发现配置,配置在bootstrap里面!!!
spring:
cloud:
nacos:
config:
enabled: false
server-addr: 127.0.0.1:8848
discovery:
server-addr: 127.0.0.1:8848
来看application
端口不说了,application.name 也不说了,重点看dubbo的标签
dubbo.consumer.check 这个代表你作为消费者,启动的时候是不是需要检查生产者是否存在?如果生产者不存在,会提示no Provider,重试3次后,消费者发现不到生产者,是无法启动的,所以为了避免这个情况
我们把这个值设置为false,表示启动的时候不检查,等到调用的时候,再去检查是否生产者存在,从而完成远程调用逻辑。建议关闭
protocol表示dubbo协议的相关内容,前面章节我说到dubbo是一种rpc框架,也是基于tcp连接,既然是网络传输,就要有自己的协议,也要对应的端口,不然你这个请求到哪里去嘛?
dubbo.registry表示dubbo注册中心的配置,用来配置连接注册中心相关的信息。因为dubbo的服务,要上注册中心,所以这里配置nacos的注册中心地址。
server:
port: 8080
spring:
application:
name: order-consumer
dubbo:
consumer:
check: false
application:
name: ${spring.application.name}
protocol:
port: 20880
name: dubbo
registry:
address: nacos://127.0.0.1:8848
简单的配置,我就介绍到这里,接下来重点来了。
有很多读者都问,微服务公司就是这么玩的吗?
回答并不是,这是最入门最初级的,但是很多行业内的人,连入门都达不到,连配置的策略都不清楚,模模糊糊的,那是不行的,最起码你要能说服你自己。
那么当你在面对不同的系统,不同的模块,要进行整体的架构更换,仅仅这点知识,是完全不够的,下面我就讲述,在实际开发中会遇到的一些点,dubbo怎么处理的!!
3、开发常见的问题
还是以这两个服务为例子
user-provider
order-consumer
调用关系是,order-consumer订单服务调用user-provider用户服务
如果我此时此刻,新增一个服务,这个服务叫做pay-provider支付服务,再新增一个存储的接口storage-api + storage-service服务,在storage-api里面既有service,又有实现类;
如下图,如果storage-api只有接口,实现类在storage-service中,我们只需要把storage-service注册上nacos就可以了。
但是如果storage-api中有默认的实现,那么user-provider和pay-provider中,该怎么暴露storage-api的接口呢?
建立的storage-api里面随便写个service和默认的实现类,这样的业务场景是很常见的,很多服务会引入这个底层storage-api包,可以使用默认实现类,也可以重写默认实现,根据自己的需求来定
那假如目前user-provider服务和pay-provider服务,都要使用这个存储,对于一个任意一个消费者我想调用你们暴露的存储接口,应该怎么做?
首先我要在user-provider服务和pay-provider服务的pom中引入这个存储的api:
光引用不行,我的需求现在是,很多服务都有这个基础包storage-api,里面有默认的实现类,对于模块来说,我不想用他的默认实现,我想自己重写实现,暴露我重写后的服务怎么办?
这样就可以了,
启动两个服务user-provider服务和pay-provider服务,pay-provider配置和user-provider一样,注意dubbo协议端口和服务的端口+服务名字!!
很明显看到,pay已经注册上去,并且provider StorageService有两个实例,很明显是来自两个不同的服务,不信你可以点击详情看下里面的内容
点击详情:
此时我有一个消费者,假设就拿上面的order-consumer,你说我要调用不同服务暴露的接口,应该怎么实现???
启动消费者,调用localhost:8080/getStorage 这个请求很多次,我们看是怎么样的一个调用方式?控制台打印的是哪个服务里面的??我们看下
结果发现两个服务都被调用了,并且你看,我点了7次,一边3一边4,其实dubbo默认是负载轮询调用,尽管是这样;这不是我们想要的效果啊~~~我想调用user-provider暴露自己写的storage接口实现的怎么办?
很简单,dubbo提供了分组策略,我只需要在不同的服务暴露的接口中,加个分组就可以
在调用方我只要指定调用的服务属于那个组就可以了!这样就可以确保调用方调用对应暴露的接口了!!