
在系列文章微服务-2中我们已经新建了父工程和子工程server-order。并将server-order注册到Nacos。这一节我们来进行实战。实战就是能够初步有微服务的架构。比如将配置多个示例把多个示例可以理解为多个服务器承载一个服务便于分担压力。比如建立一个服务提供方再建立一个服务消费方。由服务消费方在nacos中发现服务提供方并能实现调用。当然服务提供方应该有多个示例。一、为server-order配置多个示例如前所述比如订单服务访问量可能会巨大这就需要建多个服务示例然后进行负载均衡。这里做三个端口实例。1.添加启动配置选择“Edit Configurations”在对话框左侧选择“SPring Boot”。点击“”号按照图示添加8081、8082、8083三个示例。2. 打开运行服务选择“View”–“Tool Windows”–“Services”选择“Add service”将三个示例均运行。{SpringApplication.run(StoreApplication.class,args);}}4.添加配置文件application.yml同样注册到Nacosspring: cloud: nacos: discovery: server-addr: 10.50.41.17:8848 application: name: store5.启动服务参考子工程server-order添加服务端口8084启动Store服务。启动后可以在Nacos看到。假设库存服务的访问量也需要负载均衡还可以继续添加8085这个服务端口。同样将8085这个服务端口号也启动。6.添加接口/store为了能够测试库存服务是否正常运行添加一个接口/store模拟查询某一个商品编号的库存。新建架包package com.example.controller;添加控制类StoreController。代码如下packagecom.example.controller;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PathVariable;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;RestControllerRequestMapping(/store)publicclassStoreController{Value(${server.port})privateStringport;GetMapping(/{skuID})publicStringgetStoreNum(PathVariableStringskuID){return【store实例】端口:port , 查询idskuID;}}7.运行server-store服务查看接口地址栏输入http://localhost:8084/store/1运行结果如下地址栏输入http://localhost:8085/store/1运行结果如下三、新建服务消费子工程server-goods1.新建子工程server-goods2.修改pom.xml参考server-store修改pom.xml?xml version1.0 encodingUTF-8?projectxmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdparentartifactIdcloud-demo/artifactIdgroupIdcom.example/groupIdversion0.0.1-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionartifactIdserver-goods/artifactIdpropertiesmaven.compiler.source8/maven.compiler.sourcemaven.compiler.target8/maven.compiler.target/propertiesdependencies!--alibaba-nacos--dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId/dependency!--web--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!--lombok--dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependency/dependencies/project3.添加启动类GoodsApplication注意先添加包“com.example”packagecom.example;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.cloud.client.discovery.EnableDiscoveryClient;SpringBootApplicationEnableDiscoveryClientpublicclassGoodsApplication{publicstaticvoidmain(String[]args){SpringApplication.run(GoodsApplication.class,args);}}4.添加配置文件application.yml同样注册到Nacosspring: cloud: nacos: discovery: server-addr: 192.168.1.24:8848 application: name: goods server: port: 81005.添加控制器GoodsController添加接口/index。这个接口模拟查询某一商品编号的库存需要调用server-store服务。这里需要解决两个问题第一个是如何找到server-store服务。第二个是找server-store中的哪一个前面启动了两个8084和8085两个服务。1第一个问题使用RestTemplate。新建架包package com.example.controller;添加控制类StoreController。新建一个接口“/index”packagecom.example.controller;importlombok.extern.slf4j.Slf4j;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.cloud.client.ServiceInstance;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;importorg.springframework.web.client.RestTemplate;Slf4jRestControllerpublicclassGoodsController{AutowiredprivateRestTemplaterestTemplate;GetMapping(/index)publicStringindex(){Stringresultthis.restTemplate.getForObject(http://store/store/1,String.class);// 直接打印返回结果里面自带端口号log.info(本次负载均衡访问结果{},result);returnresult;}}*** 注意 “http://store/store/1”,String.class);这里访问的store是已经注册到nacos上的服务。所以服务名必须与注册时的保持一致***2第二个问题给 RestTemplate 添加拦截器整合负载均衡客户端。这里先试用LoadBalanced这个注解实现服务选择。首先pom中 添加依赖如下dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-loadbalancer/artifactId/dependency接下来新建一个配置类GoodsConfiguration代码如下packagecom.example.configuration;importorg.springframework.cloud.client.loadbalancer.LoadBalanced;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.client.RestTemplate;ConfigurationpublicclassGoodsConfiguration{BeanLoadBalancedpublicRestTemplaterestTemplate(){returnnewRestTemplate();}}6.运行服务*** 注意确保server-store的两个示例均是正常运行状态。***打开浏览器地址栏输入http://localhost:8100/index运行结果如下。刷新当前页面会发现store的两个示例是轮询模式交替访问SpringCloud LoadBalancer 默认是轮询。*** 特别注意这里实现服务发现是因为在启动类都添加了EnableDiscoveryClient这样确保到Nacos 拉取服务实例***四、使用OpenFeign 改造完整示例server-goods 消费者调用 server-store服务名store前面使用的RestTemplate 是 Spring 框架提供的一个 HTTP 客户端工具类用来在 Java 代码里发 Http 请求GET、POST、PUT、DELETE调用别的 HTTP 接口。这是一个原生负载均衡调用方式它和 LoadBalanced配合之后对 RestTemplate 做包装增加一个拦截器拦截器拦截请求解析服务名 → 去 Nacos 拿实例列表 → LoadBalancer/Ribbon 选节点 → 替换成真实 ip:port 再发起请求。接下来使用OpenFeign 改造server-goods。它是对 RestTemplate Ribbon 的进一步封装写起来更优雅。1.引入依赖server-goods 中添加!-- openfeign --dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId/dependency引入完成后记得刷新Maven。2. 启动类改动加上EnableFeignClients开启 Feign 扫描packagecom.example;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.cloud.client.discovery.EnableDiscoveryClient;importorg.springframework.cloud.openfeign.EnableFeignClients;SpringBootApplicationEnableDiscoveryClientEnableFeignClients// 开启Feign客户端扫描publicclassGoodsApplication{publicstaticvoidmain(String[]args){SpringApplication.run(GoodsApplication.class,args);}}3. 编写 Feign 接口重点新建接口 StoreFeignClient这个接口对应 server-store 里面的 Controller具体代码如下packagecom.example.feign;importorg.springframework.cloud.openfeign.FeignClient;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PathVariable;/** * Feign客户端 * name store目标服务在Nacos中的服务名和yml里spring.application.name一致 */FeignClient(namestore)publicinterfaceStoreFeignClient{// 方法签名、注解路径、参数要和服务提供者 StoreController 接口对齐GetMapping(/store/{id})StringgetStore(PathVariable(id)Longid);}4. 改造 GoodsController直接注入上面的 Feign 接口调用不再需要 RestTemplate 和它的配置类 GoodsConfiguration代码如下packagecom.example.controller;importcom.example.feign.StoreFeignClient;importlombok.extern.slf4j.Slf4j;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.cloud.client.ServiceInstance;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;importorg.springframework.web.client.RestTemplate;Slf4jRestControllerpublicclassGoodsController{/* Autowired private RestTemplate restTemplate; GetMapping(/index) public String index() { String result this.restTemplate.getForObject( http://store/store/1,String.class); // 直接打印返回结果里面自带端口号 log.info(本次负载均衡访问结果{}, result); return result; }*/// 注入Feign接口AutowiredprivateStoreFeignClientstoreFeignClient;GetMapping(/index)publicStringindex(){// 像调用本地方法一样调用远程库存接口StringresultstoreFeignClient.getStore(1L);log.info(Feign调用库存结果{},result);returnresult;}}5.运行服务*** 注意确保server-store的两个示例均是正常运行状态。***运行结果与前面的一致。*** 总结本节实战了微服务之间的调用初步有了架构概念。下一节连接上数据库实现服务配置***