从本文开始,我们将探讨在Spring Cloud Alibaba微服务组件中的另一个主打高性能RPC调用的微服务调用组件,也就是由阿里巴巴开源的,后捐献给了Apache基金会的Dubbo。在服务调用方面,Dubbo的用户体验无疑是极致的。借助Spring Cloud Alibaba项目,我们只需要几个小小的注解,便能在分分钟内搭建完成服务调用,这是否令你惊讶?简单而爽快!
本文会先从Spring Cloud与Dubbo的关系说起,再讲到Dubbo架构,然后实战落地!最后的常见问题排查绝对是新手必看!我敢说整合Dubbo时有 99% 的人会遇到!文末附源码!!!也有投票期待你的参与!
对于如何在Spring Cloud Alibaba中快速集成Apache Dubbo,我们会搭建一个全新的环境,这样你还可以复习一下Spring Cloud Alibaba环境搭建知识,并能同时在案例中学会如何调用OpenAI API 生成图片!
没有什么比图更直观的了,老哥准备了这张图,相信你能轻松对Dubbo远程调用有个大概的认识!
你是否见过下面这两类文章?
你心中是否有过 疑问
:两个框架能拿来做对比
, 说明是同类框架, 为什么又能做整合?
实际上,Apache Dubbo官方定位的是一款微服务框架,如下图,因此它和Spring Cloud都属于微服务框架,也都存在自己独特的生态
系统,所以同作为微服务框架,它们经常拿来做对比
!
另外,Dubbo最初的核心就是高性能 RPC 通信 和 自动服务发现,因此它在RPC服务调用方面做的很独立和强大,所以它又可以独立作为微服务调用组件
被整合到Spring Cloud中,这就是为什么它们又能做整合
!
对于Spring Cloud整合Dubbo,我们不看Dubbo的微服务架构,主要看它 服务发现、服务调用的架构,如下图:
主要是四方的关系:
主要干了这5件事:
-初始化
-初始化
-初始化
-异步
-同步
-异步
然后我们就可以愉快的开始实战了,Let’s Go!
引自凉哥的文章: ,推荐阅读!
所以,我们就以实现AI作图为例,看看在微服务项目中我是怎么设计的!
gg
设定需求:用户入驻后,使用OpenAI结合 [用户昵称、地域、兴趣爱好] 为用户生成[个性头像]!
仅以此抛砖引玉,你可以设计的更丰满!
gg-chatgpt
提供OpenAI能力的服务!这里用OpenAI生成个性头像!
gg-entry
提供入驻能力的服务,会调用gg-chatgpt服务
!
提前说明:服务的身份是相对的,
服务提供方
也可能是服务消费方
。主要取决于微服务的拆分!所以项目命名一般不会出现provider或consumer的关键词!
对于Spring Cloud Alibaba的版本选择
,第一篇已经有详细的说明,所以本篇对版本选择不变!
注册中心依然是使用标配的Nacos,对于Nacos-server的安装请参见第一篇:
对于dubbo的版本,spring-cloud-alibaba 2.2.7默认集成的是2.7.13
,这里升级到2.7.18
,主要是做了安全升级!
父工程只有一个pom.xml文件,主要目的是引入BOM,定义好版本,服务不必关心版本号,pom.xml
的dependencyManagement
配置如下(内有详细注释):
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring-boot.version>2.3.12.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.7.RELEASE</spring-cloud-alibaba.version>
<spring.version>5.2.21.RELEASE</spring.version>
<dubbo.version>2.7.18</dubbo.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- bom start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- duboo-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud alibab-->
<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>
<!-- spring boot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- bom end -->
<!-- dubbo start -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<!-- dubbo end -->
<!-- API start-->
<dependency>
<groupId>com.tiangang</groupId>
<artifactId>gg-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- API end -->
</dependencies>
</dependencyManagement>
API接口包,是实现RPC通信的接口定义,可以使API接口更加清晰,便于维护与管理,在OpenFeign实战中我也同样推荐过:API接口单独放在一个包里。
@Data
public class ChatGPTParamDTO implements Serializable {
private String name;
private String area;
private String hobby;
}
@Data
public class ChatGPTResultDTO implements Serializable {
private String imageUrl;
}
public interface ChatGPTService {
/**
* 生成头像
*/
ChatGPTResultDTO generateAvatar(ChatGPTParamDTO paramDTO);
}
lombok依赖是可选
的,如果你不用,就没有依赖了!
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
首先,新建一个SpringBoot程序,命名:gg-chatgpt
。
然后,在此基础上,主要实现:
spring-cloud-starter-alibaba-nacos-discovery
:用于支持Nacosspring-cloud-starter-dubbo
:用于支持dubbo<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Dubbo Spring Cloud Starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!-- Spring Cloud Nacos Service Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- API接口包 -->
<dependency>
<groupId>com.tiangang</groupId>
<artifactId>gg-api</artifactId>
</dependency>
</dependencies>
# 服务端口
server.port=8081
# 注册中心的服务名
spring.application.name=gg-chatgpt
# 注册中心地址
spring.cloud.nacos.discovery.server-addr=localhost:8848
# dubbo协议
dubbo.protocols.dubbo.name = dubbo
# dubbo协议端口( ‐1 表示自增端口,从 20880 开始)
dubbo.protocols.dubbo.port = -1
# 其它dubbo配置先不关心
# openAI配置
chatgpt.image.generation.url=https://api.openai.com/v1/images/generations
chatgpt.secret=YOUR_KEY_SECRET
这里主要是实现gg-api
接口包的ChatGPTService
,增加@DubboService
注解,用于暴露Dubbo服务.
内部使用RestTemplate
以HTTP方式调用OpenAI API
生成图片.
对于RestTemplate的用法,建议看我的博文:
当然,也可以使用OpenFeign
以RPC方式调用OpenAI API
生成图片.
对于OpenFeign实战案例,建议看我的博文:
@DubboService
public class ChatGPTServiceImpl implements ChatGPTService {
@Value("${chatgpt.image.generation.url}")
private String imageGenerationUrl;
@Value("${chatgpt.secret}")
private String secret;
@Autowired
private RestTemplate restTemplate;
@Override
public ChatGPTResultDTO generateAvatar(ChatGPTParamDTO paramDTO) {
ChatGPTResultDTO resultDTO = new ChatGPTResultDTO();
resultDTO.setImageUrl(createImage(paramDTO));
return resultDTO;
}
private String createImage(ChatGPTParamDTO paramDTO) {
String prompt = String.format("生成一张个性头像: 昵称:%s, 地区:%s, 爱好:%s"
, paramDTO.getName(), paramDTO.getArea(), paramDTO.getHobby());
return invokeChatgptCreateImage(prompt);
}
private String invokeChatgptCreateImage(String prompt) {
Map<String, Object> body = new HashMap<>();
body.put("prompt", prompt);
body.put("n", 1);
body.put("size", "256x256");
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
headers.add("Authorization", "Bearer " + secret);
HttpEntity<?> httpEntity = new HttpEntity<>(body, headers);
try {
JSONObject responseBody = restTemplate.exchange(imageGenerationUrl, HttpMethod.POST, httpEntity, JSONObject.class).getBody();
System.out.println(responseBody);
if (responseBody != null && responseBody.get("data") != null) {
return responseBody.getJSONArray("data").getJSONObject(0).get("url").toString();
}
} catch (Exception e) {
e.printStackTrace();
}
return "https:///scm_2008/article/details/128931945";
}
}
额外增加注解:
@EnableDiscoveryClient
用于服务注册和发现@EnableDubbo
用于扫描上面配置的@DubboService
注解,scanBasePackages
指定扫描的路径@SpringBootApplication
@EnableDiscoveryClient
@EnableDubbo(scanBasePackages = {"com.tiangang.gg.chatgpt.facade"})
public class ChatGPTRunner {
public static void main(String[] args) {
SpringApplication.run(ChatGPTRunner.class, args);
}
@Configuration
public class Config {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
return new RestTemplate(factory);
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(15000);
factory.setReadTimeout(30000);
return factory;
}
}
}
首先,新建一个SpringBoot程序,命名:gg-entry
。
然后,在此基础上,主要实现:
spring-cloud-starter-alibaba-nacos-discovery
:用于支持Nacos
spring-cloud-starter-dubbo
:用于支持dubbo
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Dubbo Spring Cloud Starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!-- Spring Cloud Nacos Service Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- API接口包 -->
<dependency>
<groupId>com.tiangang</groupId>
<artifactId>gg-api</artifactId>
</dependency>
</dependencies>
额外增加dubbo.cloud.subscribed-services = gg-chatgpt
,可以订阅多个提供方服务,以逗号
分隔
# 服务端口
server.port=8082
# 注册中心的服务名
spring.application.name=gg-entry
# 注册中心地址
spring.cloud.nacos.discovery.server-addr=localhost:8848
# 订阅服务提供方
dubbo.cloud.subscribed-services = gg-chatgpt
# dubbo协议
dubbo.protocols.dubbo.name = dubbo
# dubbo协议端口( ‐1 表示自增端口,从 20880 开始)
dubbo.protocols.dubbo.port = -1
# 其它dubbo配置先不关心
对于服务调用,通常都会在Service层调Dubbo服务,我这里简化只创建Controller,直接在Controller里调用Dubbo服务,目的就是为了测试验证,主要通过@DubboReference
引入dubbo服务
@Autowired
retries
:防止幂等问题设置为0:不重试timeout
: 防止调用服务超时,默认1秒,单位ms@RestController
@RequestMapping("/entry")
public class EntryController {
@DubboReference(retries = 0, timeout = 10000)
private ChatGPTService chatGPTService;
// 定义一个测试用的接口
@PostMapping("/chatgpt")
public ChatGPTResultDTO generateAvatar(@RequestBody ChatGPTParamDTO paramDTO) {
return chatGPTService.generateAvatar(paramDTO);
}
}
额外增加注解:
@EnableDiscoveryClient
用于服务注册和发现@SpringBootApplication
@EnableDiscoveryClient
public class EntryRunner {
public static void main(String[] args) {
SpringApplication.run(EntryRunner.class, args);
}
}
注意启动顺序
:先启动服务提供者gg-chatgpt
,再启动服务消费者gg-entry
。
启动后,到Nacos的服务列表,可以看到:
使用postman测试一下,达到预期~ 💪💪💪
看看结果哈,这是画吗?也太真了,反正我是看不出来 这是真人照片
还是AI的画
了…
初学者最常见的问题,也是最让人懵圈的报错:
No provider available from registry localhost:9090 for service xxx
最后,我再总结一下主要步骤,其实和本地调用相比,无外乎就是几个注解和配置的区别!
@DubboService
声明提供方的服务,与本地服务声明用@Service
对应@EnableDubbo
注解,提供DubboService@DubboReference
引入提供方的服务,与本地服务引入用@Autowired
对应dubbo.cloud.subscribed-services
配置,订阅DubboService如果你能看懂我总结的这几点,那么恭喜你,说明你对Dubbo基础应用入门了!
关注我 天罡gg 分享更多干货:
大家的「关注❤️ + 点赞👍 + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下文见!
因篇幅问题不能全部显示,请点此查看更多更全内容