04-SpringCloud Alibaba Dubbo 2025-12-07T00:57:41.592Z 2025-12-07T00:57:41.592Z 1.1k 5 分钟 China
为了项目中实现,对内RPC,对完Http的服务请求,并实现前后端分离的愿景。
目的
Spring Cloud Alibaba Dubbo 项目的目标是将 Dubbo 融入到 Spring Cloud Alibaba 生态中,使微服务之间的调用同时具备 RESTful 和
Dubbo 调用的能力。做到对业务代码无侵入,无感知;引入 JAR 包则微服务间调用使用 Dubbo,去掉 JAR 包则使用默认的 RESTful;实现参考的是
Spring Cloud 中文社区的 Spring Cloud Dubbo 项目。
注册中心
采用的Spring Cloud Alibaba Nacos的注册中心,作为Alibaba全家桶的一员,配合Dubbo具有一定的优势,nacos的是目前生命力很强的一个开源项目,相信不远的将来,nacos必定火爆。由于
Nacos、Dubbo、Spring Cloud Alibaba 都是阿里系产品,所以我们可以很容的将 Dubbo 和 Http 服务注册到 Nacos 中。
此时服务提供者即注册了 Dubbo 又注册了 Http 服务,服务消费者根据配置方式可以在 Dubbo 与 Http 调用中随意切换。
服务提供者
将一个服务拆分成两个模块,一个service-api,提供对外接口,一个service-provider,服务的实现模块。
以前服务提供者在使用 Dubbo 注册服务时,是需要使用 @Service
注解将服务注册到注册中心的(不是Spring的service,而是org.apache.dubbo.config.annotation.Service),现在改用 @FeignClient
注解来注册,将对外提供服务的接口在service-api注册,然后在service-provider中将对外的接口实现。
以 edwin-dubbo-provider-api 项目中定义的 API 接口为例
1 2 3 4 5 6 7 8 9 10 package com.lokywang.edwin.dubbo.provider.service;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.GetMapping;@FeignClient("provider") public interface ProviderService { @GetMapping("/hi") String hi () ; }
以 edwin-dubbo-service-provider 项目中实现接口为例
1 2 3 4 5 6 7 8 9 10 11 12 package com.lokywang.edwin.dubbo.service.provider.controller;import com.funtl.alibaba.dubbo.provider.service.ProviderService;import org.springframework.web.bind.annotation.RestController;@RestController public class ProviderServiceImpl implements ProviderService { @Override public String hi () { return "Hi Spring Cloud Alibaba Dubbo" ; } }
以上代码是一个典型的 Spring Cloud RESTFul API,服务提供者需要做的就是引入 Dubbo 相关依赖,扫描包含 @FeignClient 注解的类并注册到
Nacos 即可,关键代码在 spring-cloud-alibaba-dubbo-core 项目的 FeignClientToDubboProviderBeanPostProcessor 类中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 private void registerServiceBeans (Set<String> packagesToScan, BeanDefinitionRegistry registry) { DubboClassPathBeanDefinitionScanner scanner = new DubboClassPathBeanDefinitionScanner (registry, environment, resourceLoader); BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry); scanner.setBeanNameGenerator(beanNameGenerator); scanner.addIncludeFilter(new AnnotationTypeFilter (FeignClient.class, true , true )); for (String packageToScan : packagesToScan) { scanner.scan(packageToScan); Set<BeanDefinitionHolder> beanDefinitionHolders = findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator); if (!CollectionUtils.isEmpty(beanDefinitionHolders)) { for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) { registerServiceBean(beanDefinitionHolder, registry, scanner); } if (logger.isInfoEnabled()) { logger.info(beanDefinitionHolders.size() + " annotated Dubbo's @Service Components { " + beanDefinitionHolders + " } were scanned under package[" + packageToScan + "]" ); } } else { if (logger.isWarnEnabled()) { logger.warn("No Spring Bean annotating Dubbo's @Service was found under package[" + packageToScan + "]" ); } } } }
服务消费者
服务消费者需要依赖 edwin-dubbo-provider-api,并直接使用 @Autowired 注解即可实现注入,可以不使用 Dubbo
提供的 @Reference 注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.lokywang.edwin.dubbo.consumer.service;import com.funtl.alibaba.dubbo.provider.service.ProviderService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;@RestController public class TestService { @Autowired private ProviderService providerService; @GetMapping("/test") public String test () { return providerService.hi(); } }
以上代码是一个典型的 Spring Cloud Feign 调用。我们只需要替换 Feign 的实现。产生 ProviderService 接口的 ProxyBean 时,使用
Dubbo 产生的 Bean 替换默认的 Feign 产生的 RESTFul 调用的 Bean 即可,关键代码在 spring-cloud-alibaba-dubbo-core
项目的 DubboFeignBuilder 类中:
1 2 3 4 5 6 7 8 9 10 11 12 13 @Override public <T> T target (Target<T> target) { ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder .create(defaultReference, target.getClass().getClassLoader(), applicationContext) .interfaceClass(target.type()); try { T object = (T) beanBuilder.build().getObject(); return object; } catch (Exception e) { throw new RuntimeException (e); } }
消费者使用 RESTFul 调用
只需将 Dubbo 相关依赖排除即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <dependency > <groupId > com.funtl</groupId > <artifactId > spring-cloud-alibaba-dubbo-starter</artifactId > <exclusions > <exclusion > <groupId > com.funtl</groupId > <artifactId > spring-cloud-alibaba-dubbo-core</artifactId > </exclusion > <exclusion > <groupId > com.alibaba.boot</groupId > <artifactId > dubbo-spring-boot-starter</artifactId > </exclusion > </exclusions > </dependency >