微服务设计中的两个重要的项目:Spring Cloud 及Spring Cloud Alibaba,我们需要从理论角度作个整体性掌握,后续进入开发实战作好铺垫工作。为后续的微服务工具的选择和开发选择好的相关的准备。本博文将详细的介绍的Spring Cloud 及Spring Cloud Alibaba的微服务设计。
它是由很多个组件共同组成的一套微服务技术体系解决方案,目前最新版本是 Hoxton,它的版本并不是我们常见的大版本、小版本的数字形式,Spring Cloud 的版本规划是按伦敦地铁站的名称先后顺序来规划的,目的是为了更好的管理每个 Spring Cloud 子项目的版本,避免自己的版本与子项目的版本号混淆,所以要特别注意两个项目的版本对应情况,以免实际应用中产生不必要的麻烦。随着新版本的迭代更新,有些低版本的 Spring Cloud 的不建议再应用于生产,比如 Brixton 和 Angel 两个版本在 2017 年已经寿终正寝。
( 某 Spring Cloud Greenwich 版本与子项目的版本对应情况 ) Spring Cloud 基于 Spring Boot 对外提供一整套的微服务架构体系的解决方案,包括配置管理、服务注册与服务发现、路由、端到端的调用、负载均衡、断路器、全局锁、分布式消息等,对于这些功能 Spring Cloud 提供了多种项目选择,可从官网的主要项目列表一窥端倪。
看上图有个比较突出的子项目: Spring Cloud netflix,由 Netflix 开发后来又并入 Spring Cloud 大家庭,它主要提供的模块包括:服务发现、断路器和监控、智能路由、客户端负载均衡等。但随着 Spring Cloud 的迭代,不少 Netflix 的组件进行了维护模式,最明显的莫过于 Spring Cloud Gateway 的推出来替代旧有的 Zuul 组件,有项目加入,也会有老旧项目退出舞台,这也是产品迭代的正常节奏。这些子项目,极大的丰富了 Spring Cloud 在微服务领域中应用范围,几乎无需要借助外部组件,以一已之力打造全生态的微服务架构,并与外部基础运维组件更好的融合在一起。
官网地址:https://github.com/alibaba/spring-cloud-alibaba 它是 Spring Cloud 的一个子项目,致力于提供微服务开发的一站式解决方案,项目包含开发分布式应用服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务,只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里分布式应用解决方案,通过阿里中间件来迅速搭建分布式应用系统。 项目特性见下图:
包括一些关键组件:
以上组件都均是开源实现方案。下面提到的几个组件都是结合阿里云的产品形态完成的功能,后续的案例开发实战不引入商业产品,需要的小伙伴购买后拿到对应的 API 直接接入即可。
在使用过程中,版本问题同样需要关注。
不管是 Spring Cloud 还是 Spring Cloud Alibaba 项目,都是基于 Spring Boot ,所以先将 Spring Boot 掌握后,才能更好的应用这两个项目。提供的大量的 starter 组件,更是方便我们快速的应用相应的功能,由于其内置了应用容器( Tomcat ,Jetty ,Undertow ),无须再构建成 war 文件去部署,并遵从约定优于配置的原则,高效开发应用。下面的链接是一份 Spring Boot 的全量参数配置,相信对你会有帮助。 Common Application properties。
微服务开发选型,到底是基于 Dubbo 还是 Spring Cloud,相信不少开发的小伙伴都有拿这两个项目作过作比较的经历。
我们还是先来看看 Dubbo 的发展历史:
Dubbo 定位于高性能、轻量级的开源 Java RPC 框架,随着社区的不断丰富,Dubbo 生态越来越繁荣。
官方为快速开发者上手 Dubbo 应用,仿照 start.spring.io,推出快速生成基于 Spring Boot 的 Dubbo 项目的网站:http://start.dubbo.io/。更详细的文档,可到官网查看。Spring Cloud 的历史很短,Spring Cloud 源于 Spring,来梳理下 Spring 的发展情况:
从漫长的发展历史中,可见 Spring 的发展也是一波三折。事实上,做 Java 开发基本绕不开 Spring,Spring 社区对 Java 的发展有着极大的影响力,而 Spring Cloud 则是基于 Spring、 Spring Boot 生态提供了一整套开箱即用的全家桶式的解决方案,极大的方便了开发者快速上手微服务开发,背后的商业公司更是为其提供了强大的支撑,同时不少核心项目组件能看到 Netflix OSS 的身影,如 Eureka 等,均在 Netflix 线上的分布式生产环境中已经得到很好的技术验证,无形中增强了信用背书。
Dubbo 在国内有较大的市场影响力,但国际市场上 Spring Cloud 的占有率要比 Dubbo 大,毕竟原生的英文环境及 Spring 社区的庇荫都是生态繁荣的优势。随着 Dubbo 正式成为 Apache 顶级项目后,相信未来在国际市场上的采用度会越来越高。
二者的交集是发现在 2015 年左右,一方面 Dubbo 在国内应用广泛,以简单易上手、高性能著称,遗憾之处在于社区几乎停滞。而此时 Spring Cloud 以全新姿态面世,基于 Spring Boot 的约定优于配置的原则,在 Java 轻量级开发中迅速传播开来,但组件种类多、资料少、学习曲线高也是不争的事实。
早期大家做技术选型时,经常会将二者拿出来作比较,典型的可参照:《微服务架构的基础框架选择:Spring Cloud 还是 Dubbo?》一文。2016 年公司在做技术选型时,我同样也面临这个问题,鉴于当时的业务需求及团队的技术储备能力,最终还是选择了处在非维护期的 Dubbo,后期无法满足需求时再考虑重构。
Spring Cloud 早期的服务注册中心是基于 Eureka,Dubbo 采用的注册中心是 ZooKeeper,一套服务存在两个服务管理方案,复杂度相当高,又各自在各自的领域内,有各自的解决方案,要整合起来,也非易事。
近两年来 Spring Cloud Alibaba 的出现,这种二选一的局面得到了极大的改善。一方面,可以替代原项目中一些不再维护的项目功能。另一方面,可以将阿里技术生态与 Spring Cloud 生态融合起来。二者都可以采用 Nacos 作为服务注册中心,同时也完美替代 Spring Cloud Config 提供了更简洁直观的配置管理,降低了复杂度。另外,也为 Spring Cloud 生态中也引入了 RPC 解决方案——Dubbo,与 REST 方式形成互补。
现在我们就通过一个业务功能——会员通过积分兑换来洗车券去洗车,将两个项目融合在一起。
新增 parking-carwash 父项目:此模块需要完成对外提供 RPC 接口的功能,代码结构如下
下属两个子项目模块,api 项目只是简单的 Java 项目,构建成 jar 包供外部项目依赖调用,serv 项目基于 Spring Boot 提供实际业务服务,以 jar 的形式独立运行。
parking-carwash-serv 服务提供者
在 api 模块中编写接口,同时将对应的实体放在这里,以便被依赖时正常使用。参照之前的方式配置基本的基础组件,再引入 Dubbo 相关的 jar,配置如下:
- <!-- 必须包含 spring-boot-starter-actuator 包,不然启动会报错。 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-actuator</artifactId>
- </dependency>
-
- <!-- Dubbo Spring Cloud Starter -->
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-dubbo</artifactId>
- </dependency>
为体验下 yml 配置文件的应用情况,本项目中引入 bootstrap.yml 文件,完全可以采用一个 application 配置文件:
- spring:
- application:
- name: carwash-service
- main:
- allow-bean-definition-overriding: true
- cloud:
- nacos:
- discovery:
- enabled: true
- register-enabled: true
- server-addr: 127.0.0.1:8848
application.properties 中配置 Dubbo:
- # dubbo config
- dubbo.protocols.dubbo.name=dubbo
- dubbo.protocols.dubbo.port=-1
- dubbo.scan.base-packages=com.mall.parking.carwash.serv.service
- dubbo.registry.address=spring-cloud://127.0.0.1
- dubbo.registry.register=true
- dubbo.application.qos.enable=false
-
- #此配置项为了防止 nacos 大量的 naming 日志输出而配置
- logging.level.com.alibaba.nacos.client.naming=error
编写接口及实现类:
- public interface WashService {
- int wash(String json) throws BusinessException;
- }
-
- @Service(protocol = "dubbo")
- @Slf4j
- public class WashServiceImpl implements WashService {
-
- @Autowired
- CarWashMapper carWashMapper;
-
- @Override
- public int wash(String json) throws BusinessException {
- CarWash carWash = JSONObject.parseObject(json, CarWash.class);
- int rtn = carWashMapper.insertSelective(carWash);
- log.info("car wash data = " + json + "> write suc...");
-
- return rtn;
- }
-
- }
注意:@Service 注解不再使用 Spring 的,而是采用 Dubbo 提供的注解 org.apache.dubbo.config.annotation.Service,注释中同时提供了多种属性值,用于配置接口的多种特性,比如服务分组、服务版本、服务注册是否延迟、服务重试次数等等,依实际使用情况而定。
Application 启动类,与一般 Spring Cloud 的启动类无异。启动后,在 Nacos 的服务列表中可以看到本模块的服务已经注册成功。
parking-member 服务消费者
在前期构建完成的 parking-member 项目中引入 Dubbo 的 jar 和 api 接口 jar。
- <!-- Dubbo Spring Cloud Starter -->
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-dubbo</artifactId>
- </dependency>
- <dependency>
- <groupId>com.mall.parking.root</groupId>
- <artifactId>parking-carwash-api</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- </dependency>
- application.properties 配置:
-
- #dubbo config
- dubbo.registry.address=nacos://localhost:8848
- dubbo.application.qos.enable=false
- dubbo.cloud.subscribed-services=carwash-service
- spring.main.allow-bean-definition-overriding=true
- #不检测服务提供者是否在线,生产环境建议开启
- dubbo.consumer.check=false
-
- #more naming logs output,config this to avoid more log output
- logging.level.com.alibaba.nacos.client.naming=error
编写服务调用类:
- @Reference
- WashService washService;//像调用本地 jar 一样,调用服务
-
- /**
- * {"plateNo":"湘 AG7890","ticketCode":"Ts0999"}
- *
- * @param json
- * @return
- * @throws BusinessException
- */
- @PostMapping("/wash")
- public CommonResult<Integer> wash(String json) throws BusinessException {
- log.debug("add vehicle = " + json);
- CommonResult<Integer> result = new CommonResult<>();
-
- int rtn = washService.wash(json);
- result.setRespData(rtn);
- return result;
- }
测试
服务提供者启动后,再启动会员模块服务,使用 Postman,访问 vehicle/wash 方法,可以看到服务正常调用,数据写入 park-carwash 数据库。至此,我们将 Dubbo 与 Spring Cloud 两大项目完美整合到一个项目中,项目中既可以用到 RPC 框架的高效能,也可以享受到全家桶的便利性。
有两种引入 Dubbo 的 starter 方式,spring-cloud-starter-dubbo 和 dubbo-spring-boot-starter,这两种方式有什么区别呢?