![微服务从小白到专家:Spring Cloud和Kubernetes实战](https://wfqqreader-1252317822.image.myqcloud.com/cover/981/41202981/b_41202981.jpg)
5.8 改造coupon-user-service服务
5.8.1 添加依赖项和配置项
仿照coupone-template-service和coupon-calculation-service的改造步骤,添加eureka-client的依赖项到coupon-user-service项目下的pom.xml文件中,在com.broadview.coupon.user包路径下创建启动类CouponUserApplication。将coupon-template-service项目的配置文件application.yml复制到coupon-user-service项目中,在复制后的application.xml文件中我们只需更改应用名称和端口号,其他内容不变,相关代码如下:
![](https://epubservercos.yuewen.com/91A00C/21440188001525406/epubprivate/OEBPS/Images/251-2.jpg?sign=1739419994-Pze8IblPrMjml363Dr8tAqc7csTAVl55-0-9dc79972066cced04dcd85eb2f8ea841)
5.8.2 声明RestTemplate
Spring提供了一个轻量级的HTTP调用工具类org.springframework.web.client. RestTemplate,我们可以在coupon-user-service项目中通过RestTemplate向其他应用发起HTTP调用。打开CouponUserApplication类,使用@Bean注解声明一个RestTemplate类的对象,具体实现代码如下:
![](https://epubservercos.yuewen.com/91A00C/21440188001525406/epubprivate/OEBPS/Images/252-1.jpg?sign=1739419994-kPRQRsN4DeC65YqLz5Qt0uiOPNIQRduF-0-9e40b0f951f1e73facbacfb711c62545)
5.8.3 改造findCoupon()方法——RestTemplate.exchange函数的用法
由于service层已经被拆分到各个微服务模块中,无法通过注入service对象的方式直接发起本地方法调用,所以我们需要通过RestTemplate发起远程调用。在本节中我们将分别用多种不同的集成方式来演示RestTemplate的用法。
接下来,我们通过三个步骤来改造UserServiceImpl类的findCoupon()方法,具体步骤如下。
1. 依赖注入
找到UserServiceImpl类,将无效引用删除以后,通过@Autowired注解将RestTemplate和LoadbalancerClient对象注入UserServiceImpl类中,具体代码如下:
![](https://epubservercos.yuewen.com/91A00C/21440188001525406/epubprivate/OEBPS/Images/252-2.jpg?sign=1739419994-4cSraR1EGm0jCm60Taq7KtNMQ1XC5gIv-0-4a1e420518d65f0f515ca7bb5bafdf17)
RestTemplate类用来发起远程HTTP调用,LoadBalancerClient类可以通过负载均衡策略获取可用的服务节点的地址信息。
2. 添加寻址方法
在UserServiceImpl类中加入两个新方法,这两个方法分别用来拼接访问地址和组装HttpHeader信息,具体代码如下:
![](https://epubservercos.yuewen.com/91A00C/21440188001525406/epubprivate/OEBPS/Images/252-3.jpg?sign=1739419994-uuRWD9gvRKjT1uLOvSxbual0IzDWlUPh-0-9c5dd3f18421e5141e4082cd610539f0)
![](https://epubservercos.yuewen.com/91A00C/21440188001525406/epubprivate/OEBPS/Images/253-1.jpg?sign=1739419994-WJFWlTSPFkBOMnqKtW0lJIzmxGcHjGHL-0-61b4f099d6a93fa5f7f75e33b0109511)
在上面的代码中,getUrl()方法的serviceId必须与目标服务的注册名称(即application.yml文件中定义的application.name属性)相同,LoadBalancerClient对象会基于服务发现获取的机器列表,通过负载均衡选定一个可用地址并返回。
3. 使用RestTemplate替换本地方法调用
最后一步是替换本地方法调用,通过resetTemplate的exchange()方法来发起一个HTTP调用,具体代码如下:
![](https://epubservercos.yuewen.com/91A00C/21440188001525406/epubprivate/OEBPS/Images/253-2.jpg?sign=1739419994-pH1hqwwIRGnGwnqFzfiyOMnuAUyUYaMm-0-89ba976beb39547d7ac8675522b53acc)
![](https://epubservercos.yuewen.com/91A00C/21440188001525406/epubprivate/OEBPS/Images/254-1.jpg?sign=1739419994-crphgRFbk0NN1fgMwQrsqQzUBYHwW8db-0-3e0df23284e4e303a06df7c699badc76)
RestTemplate中的exchange()方法可以支持任意类型(GET、POST、DELETE和PUT)的HTTP请求,上面代码中传入exchange()方法的参数从左到右依次为:目标访问地址、HTTP请求类型、请求内容(header+body)和返回值类型。Exchange()方法不会直接返回业务对象,而是通过一个ResponseEntity对象将业务对象封装起来,我们可以通过getBody()方法从ResponseEntity对象中获取最终的返回结果。
5.8.4 改造requestCoupon()方法——getForObject函数的用法
打开UserServiceImpl类的requestCoupon()方法,使用RestTemplate.getForObject()方法替换当前方法内的本地调用,具体代码如下:
![](https://epubservercos.yuewen.com/91A00C/21440188001525406/epubprivate/OEBPS/Images/254-2.jpg?sign=1739419994-VXqDmWIzXp6Kh1XDvSqDA5Y8OBQcOb2A-0-0f97f872016aa0cafa678e55b3ab7d94)
5.8.5 改造placeOrder()方法
UserServiceImpl类的placeOrder()方法同时对coupon-template-service和coupon-calculation-service发起了调用,下面分别使用getForObject()和postForObject()方法对两处方法调用进行替换,具体代码如下:
![](https://epubservercos.yuewen.com/91A00C/21440188001525406/epubprivate/OEBPS/Images/255-2.jpg?sign=1739419994-4boisfF2QNeoz3OXPzemG6A9v1uF6Jdk-0-c6145624749e189e5e1abde911453692)
在调用coupon-tempalte-service的时候,我们没有将查询参数直接写入URL中,而是通过一个外部Map对象传递Request参数,RestTemplate可以自动把URL中定义的占位符(如代码中定义的{id})替换为Map中的参数,Map对象中的key就对应了URL中占位符的属性名。
5.8.6 启动项目并验证服务注册
我们分别启动eureka-server和eureka-server2两个注册中心,待注册中心启动完成后再依次启动coupon-template-service、coupon-calculator-service和coupon-user-service三个应用。待所有应用启动完成后,在浏览器打开注册中心页面http://peer1:10000/eureka,可以看到所有服务都显示在页面上了,改造完成后的服务注册表如图5-7所示。
![](https://epubservercos.yuewen.com/91A00C/21440188001525406/epubprivate/OEBPS/Images/256-01.jpg?sign=1739419994-5ck9wcNfqXoNviYu0HW94Raw2Z7beei5-0-532a6327c9a9f253efdbb93fc076e3f7)
图5-7 改造完成后的服务注册表
注册中心验证通过以后,我们在本地可以通过Postman等工具向coupon-user-service发起服务调用请求,验证改造后的服务是否能正确工作。
如果coupon-user-service在调用其他服务的时候抛出异常,可能是以下几个原因造成的:
(1)传入LoadBalancerClient的Service ID不正确,或者远程方法的访问路径不正确。
(2)对应服务没有注册,检查注册中心页面,查看当前服务状态。
(3)服务已经注册,但注册信息还没被coupon-user-service通过服务发现机制拉取到,等下次服务发现执行后重新发起一次调用即可。