前言
上次学习了SpringCloudAlibaba的注册中心+配置中心Nacos,写了一个小Demo,对SpringCloudAlibaba有了一个基本的认知。这次将引入Dubbo,实现服务间的调用。
在接触SpringCloudAlibaba之前,微服务之间的调用,我们最常用的可能是Feign。在上次的Demo中,用的则是LoadBalance的方式。这一次,将试着用Dubbo来实现微服务之间的调用。Dubbo采用RPC的方式来调用,不需要去了解它的底层细节,调用其他服务的方法,就像调用自己的服务本地的方法一样,非常简单自然。比起Feign来说,要更加的直观。而且Dubbo也要求采用接口的方式进行调用,这也是面向接口编程的一种体现。话不多说,我们开始着手改造,将上次的小Demo引入Dubbo吧。
先抽取接口吧
我们上次的Demo,写了一个服务提供者和一个服务消费者,通过LoadBalance的方式进行调用。既然要使用Dubbo,就需要将服务提供者的服务,抽象成一个公共的接口,再由服务提供者和消费者分别进行引用。
首先,我们要新建一个Module作为公共的接口,两个服务都需要引用这个Module。命名为nacos-public-interface。这个Module的pom文件不需要引入什么额外的依赖,我这里只引入了一个lombok的依赖。
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
我们之前的服务,是将返回结果包装成一个实体类进行返回的。那么既然要抽取接口,这个实体类也应该被抽取出来,放在公共的接口中。还有一点需要注意,实体类需要实现Serializable接口,以供序列化
package com.akitsuki.entity;
import lombok.Data;
import java.io.Serializable;
/**
* @author ziling.wang@hand-china.com
* @date 2022/9/27 15:22
*/
@Data
public class EntityInfo implements Serializable {
private String entityId;
private String info;
private String sendTime;
}
然后,将之前的查询方法,包装成接口,我们的这个公共接口Module就算完成了
package com.akitsuki;
import com.akitsuki.entity.EntityInfo;
/**
* @author ziling.wang@hand-china.com
* @date 2022/10/13 16:43
*/
public interface IEntityService {
/**
* 查询entity 信息
* @return
*/
EntityInfo queryEntityInfo(String entityId);
}
接口抽取完了,我们还需要让生产者和消费者分别引用这个接口的依赖,并且移除掉生产者项目中本来的实体类
<dependency>
<groupId>com.akitsuki</groupId>
<artifactId>nacos-public-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
开始引入Dubbo依赖
我在操作过程中,发现Dubbo的依赖不是很好拉,所以我加上了阿里云的仓库
<repositories>
<repository>
<id>aliyun</id>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
然后是在父项目的dependencyManagement中,加入dubbo-bom的管理,这里我们用3.0.7版本的dubbo,比较新
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-bom</artifactId>
<version>3.0.7</version>
<type>pom</type>
<scope>import</scope>
</dependency>
关于Dubbo的依赖,这里主要有以下三个:
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.0.4</version>
</dependency>
首先肯定是spring-boot的starter,然后由于我们的注册中心使用的是nacos,所以这里也需要引入dubbo注册到nacos的依赖。最后则是nacos-client的依赖,这个依赖非常关键,在我做这个demo的时候,有很多bug都是这个依赖所引起的。首先,必须要引入这个依赖。然后,依赖的版本号也很关键。和3.0.7的Dubbo相匹配的nacos-client,经过我多次实验,就是2.0.4。如果采用其他的版本或者不引入,一般会出现一些class not found之类的报错,或者其他的奇怪错误。
配置文件
dubbo其实提供了很多配置项,但这里我们要实现小demo,只需要不多的几个即可。
dubbo:
application:
name: dubbo-provider
protocol:
name: dubbo
port: -1
registry:
address: nacos://localhost:8858
可以看到,这里设置了应用名、协议、端口、注册中心地址。这里给出的是生产者的配置,消费者只需要修改一下name即可。这里的端口设置成-1,代表自动选择端口,会从20880开始,由系统自动进行管理。
生产者的改造
生产者的改造主要是将之前的Service实现我们抽取出的公共接口,并且在类上加一个注解@DubboService,来指明当前的类是用于提供给Dubbo服务的,别的服务可以通过Dubbo来调用到这个类。
package com.akitsuki.service;
import com.akitsuki.IEntityService;
import com.akitsuki.entity.EntityInfo;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.stereotype.Service;
/**
* @author ziling.wang@hand-china.com
* @date 2022/9/27 15:23
*/
@DubboService
@Service
public class EntityInfoService implements IEntityService {
@Override
public EntityInfo queryEntityInfo(String entityId) {
EntityInfo entityInfo = new EntityInfo();
entityInfo.setEntityId(entityId);
entityInfo.setInfo("Hello Nacos");
entityInfo.setSendTime(String.valueOf(System.currentTimeMillis()));
return entityInfo;
}
}
消费者的改造
消费者的改造要更加简单,就像我们使用依赖注入,注入一个Bean一样。我们可以使用@DubboReference注解来注入这个公共接口。然后,就可以像普通的Bean一样进行使用了,非常方便。
package com.akitsuki.controller;
import com.akitsuki.IEntityService;
import com.alibaba.fastjson.JSON;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
* @author ziling.wang@hand-china.com
* @date 2022/9/27 16:43
*/
@RestController
public class EntityInfoController {
@Autowired
private RestTemplate restTemplate;
@DubboReference
private IEntityService entityService;
@GetMapping(value = "/entityInfo/{entityId}")
public String getEntityInfo(@PathVariable("entityId") String entityId) {
String url = "http://nacos-provider/entityInfo/" + entityId;
return restTemplate.getForEntity(url, String.class).getBody();
}
@GetMapping(value = "/entityInfo/dubbo/{entityId}")
public String getEntityInfoByDubbo(@PathVariable("entityId") String entityId) {
return JSON.toJSONString(entityService.queryEntityInfo(entityId));
}
}
测试!
我们先启动nacos,然后分别启动生产者和消费者,可以从nacos的服务管理中看到生产者和消费者,以及Dubbo的一些注册。
试着调用一下我们新加的通过Dubbo进行调用的接口
很好,完美运行。这样我们就实现了Dubbo与Nacos的整合,在SpringCloudAlibaba的道路上又前进了一步。