SA实战 ·《SpringCloud Alibaba实战》第8章(二)

Pike_Chen
发布于 2022-5-31 16:31
浏览
0收藏

 

接下来,实现的逻辑在订单微服务的io.binghe.shop.order.service.impl.OrderServiceV4Impl类中,并且在OrderServiceV4Impl类上会标注@Service("orderServiceV4")注解。订单微服务的代码结构如下所示。

├─shop-order
│  │  pom.xml
│  │  shop-order.iml
│  │
│  └─src
│      └─main
│          ├─java
│          │  └─io
│          │      └─binghe
│          │          └─shop
│          │              │  OrderStarter.java
│          │              │
│          │              └─order
│          │                  ├─config
│          │                  │      LoadBalanceConfig.java
│          │                  │
│          │                  ├─controller
│          │                  │      OrderController.java
│          │                  │
│          │                  ├─mapper
│          │                  │      OrderItemMapper.java
│          │                  │      OrderMapper.java
│          │                  │
│          │                  └─service
│          │                      │  OrderService.java
│          │                      │
│          │                      └─impl
│          │                              OrderServiceV1Impl.java
│          │                              OrderServiceV2Impl.java
│          │                              OrderServiceV3Impl.java
│          │                              OrderServiceV4Impl.java
│          │
│          └─resources
│              │  application.yml
│              │
│              └─mapper
│                      OrderItemMapper.xml
│                      OrderMapper.xml

 

在OrderServiceV4Impl类中删除如下代码。

@Autowired
private DiscoveryClient discoveryClient;

private String getServiceUrl(String serviceName){
    List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
    int index = new Random().nextInt(instances.size());
    ServiceInstance serviceInstance = instances.get(index);
    String url = serviceInstance.getHost() + ":" + serviceInstance.getPort();
    log.info("负载均衡后的服务地址为:{}", url);
    return url;
}

在saveOrder()方法中删除如下两行代码。

//从Nacos服务中获取用户服务与商品服务的地址
String userUrl = this.getServiceUrl(userServer);
String productUrl = this.getServiceUrl(productServer);

修改通过restTemplate调用用户微服务和商品微服务的方法。修改前的代码如下所示。

User user = restTemplate.getForObject("http://" + userUrl + "/user/get/" + orderParams.getUserId(), User.class);
if (user == null){
    throw new RuntimeException("未获取到用户信息: " + JSONObject.toJSONString(orderParams));
}
Product product = restTemplate.getForObject("http://" + productUrl + "/product/get/" + orderParams.getProductId(), Product.class);
if (product == null){
    throw new RuntimeException("未获取到商品信息: " + JSONObject.toJSONString(orderParams));
}

//#####################此处省略N行代码#########################

Result<Integer> result = restTemplate.getForObject("http://" + productUrl + "/product/update_count/" + orderParams.getProductId() + "/" + orderParams.getCount(), Result.class);
if (result.getCode() != HttpCode.SUCCESS){
    throw new RuntimeException("库存扣减失败");
}

 

修改后的代码如下所示。

User user = restTemplate.getForObject("http://" + userServer + "/user/get/" + orderParams.getUserId(), User.class);
if (user == null){
    throw new RuntimeException("未获取到用户信息: " + JSONObject.toJSONString(orderParams));
}
Product product = restTemplate.getForObject("http://" + productServer + "/product/get/" + orderParams.getProductId(), Product.class);
if (product == null){
    throw new RuntimeException("未获取到商品信息: " + JSONObject.toJSONString(orderParams));
}

//#####################此处省略N行代码#########################

Result<Integer> result = restTemplate.getForObject("http://" + productServer + "/product/update_count/" + orderParams.getProductId() + "/" + orderParams.getCount(), Result.class);
if (result.getCode() != HttpCode.SUCCESS){
    throw new RuntimeException("库存扣减失败");
}

 

接下来,将io.binghe.shop.order.controller.OrderController类中的OrderService修改为注入beanName为orderServiceV4的OrderService对象,如下所示。

@Autowired
@Qualifier(value = "orderServiceV4")
private OrderService orderService;

至此,订单微服务的代码修改完成。

测试负载均衡效果
启动订单微服务,并在浏览器或其他测试工具中多次访问链接http://localhost:8080/order/submit_order?userId=1001&productId=1001&count=1,启动的每个用户微服务和商品微服务都会打印相关的日志,说明使用Ribbon实现了负载均衡功能。

注意:这里就不粘贴测试时每个启动的微服务打印的日志了,小伙伴们可自行测试并演示效果。

使用Fegin实现负载均衡
Fegin是SpringCloud提供的一个HTTP客户端,但只是一个声明式的伪客户端,它能够使远程调用和本地调用一样简单。阿里巴巴开源的Nacos能够兼容Ribbon,而Fegin又集成了Ribbon,所以,使用Fegin也能够实现负载均衡。

修改订单微服务代码
(1)在订单微服务的pom.xml文件中添加Fegin相关的依赖,如下所示。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

(2)在订单微服务的启动类io.binghe.shop.OrderStarter 上添加 @EnableFeignClients 注解,如下所示。

/**
 * @author binghe
 * @version 1.0.0
 * @description 订单服务启动类
 */
@SpringBootApplication
@EnableTransactionManagement(proxyTargetClass = true)
@MapperScan(value = { "io.binghe.shop.order.mapper" })
@EnableDiscoveryClient
@EnableFeignClients
public class OrderStarter {
    public static void main(String[] args){
        SpringApplication.run(OrderStarter.class, args);
    }
}

 

(3)在订单微服务工程shop-order下新建io.binghe.shop.order.fegin包,并在io.binghe.shop.order.fegin下新建UserService接口,并在UserService接口上标注@FeignClient("server-user")注解,其中注解的value属性为用户微服务的服务名称。UserService接口用来远程调用用户微服务的接口,源码如下所示。

/**
 * @author binghe (公众号:冰河技术)
 * @version 1.0.0
 * @description 调用用户微服务的接口
 */
@FeignClient("server-user")
public interface UserService {
    @GetMapping(value = "/user/get/{uid}")
    User getUser(@PathVariable("uid") Long uid);
}

(4)在io.binghe.shop.order.fegin下新建ProductService接口,并在ProductService接口上标注@FeignClient("server-product")注解,其中注解的value属性为商品微服务的服务名称。ProductService接口用来远程调用商品微服务的接口,源码如下所示。

/**
 * @author binghe (公众号:冰河技术)
 * @version 1.0.0
 * @description 调用商品微服务的接口
 */
@FeignClient("server-product")
public interface ProductService {

    /**
     * 获取商品信息
     */
    @GetMapping(value = "/product/get/{pid}")
    Product getProduct(@PathVariable("pid") Long pid);

    /**
     * 更新库存数量
     */
    @GetMapping(value = "/product/update_count/{pid}/{count}")
    Result<Integer> updateCount(@PathVariable("pid") Long pid, @PathVariable("count") Integer count);
}

 

(5)接下来,实现的逻辑在订单微服务的io.binghe.shop.order.service.impl.OrderServiceV5Impl类中,并且在OrderServiceV5Impl类上会标注@Service("orderServiceV5")注解。订单微服务的代码结构如下所示。

├─shop-order
│  │  pom.xml
│  │  shop-order.iml
│  │
│  ├─src
│  │  └─main
│  │      ├─java
│  │      │  └─io
│  │      │      └─binghe
│  │      │          └─shop
│  │      │              │  OrderStarter.java
│  │      │              │
│  │      │              └─order
│  │      │                  ├─config
│  │      │                  │      LoadBalanceConfig.java
│  │      │                  │
│  │      │                  ├─controller
│  │      │                  │      OrderController.java
│  │      │                  │
│  │      │                  ├─fegin
│  │      │                  │      ProductService.java
│  │      │                  │      UserService.java
│  │      │                  │
│  │      │                  ├─mapper
│  │      │                  │      OrderItemMapper.java
│  │      │                  │      OrderMapper.java
│  │      │                  │
│  │      │                  └─service
│  │      │                      │  OrderService.java
│  │      │                      │
│  │      │                      └─impl
│  │      │                              OrderServiceV1Impl.java
│  │      │                              OrderServiceV2Impl.java
│  │      │                              OrderServiceV3Impl.java
│  │      │                              OrderServiceV4Impl.java
│  │      │                              OrderServiceV5Impl.java
│  │      │
│  │      └─resources
│  │          │  application.yml
│  │          │
│  │          └─mapper
│  │                  OrderItemMapper.xml
│  │                  OrderMapper.xml

 

修改OrderServiceV5Impl类的代码,修改前的代码如下所示。

@Autowired
private RestTemplate restTemplate;

private String userServer = "server-user";
private String productServer = "server-product";

修改后的代码如下所示。

@Autowired
private UserService userService;
@Autowired
private ProductService productService;

修改OrderServiceV5Impl类中saveOrder()的代码,修改前的代码如下所示。

User user = restTemplate.getForObject("http://" + userServer + "/user/get/" + orderParams.getUserId(), User.class);
if (user == null){
    throw new RuntimeException("未获取到用户信息: " + JSONObject.toJSONString(orderParams));
}
Product product = restTemplate.getForObject("http://" + productServer + "/product/get/" + orderParams.getProductId(), Product.class);
if (product == null){
    throw new RuntimeException("未获取到商品信息: " + JSONObject.toJSONString(orderParams));
}

//##################此处省略N行代码########################

Result<Integer> result = restTemplate.getForObject("http://" + productServer + "/product/update_count/" + orderParams.getProductId() + "/" + orderParams.getCount(), Result.class);
if (result.getCode() != HttpCode.SUCCESS){
    throw new RuntimeException("库存扣减失败");
}

 

修改后的代码如下所示。

User user = userService.getUser(orderParams.getUserId());
if (user == null){
    throw new RuntimeException("未获取到用户信息: " + JSONObject.toJSONString(orderParams));
}
Product product = productService.getProduct(orderParams.getProductId());
if (product == null){
    throw new RuntimeException("未获取到商品信息: " + JSONObject.toJSONString(orderParams));
}

//##################此处省略N行代码########################

Result<Integer> result = productService.updateCount(orderParams.getProductId(), orderParams.getCount());
if (result.getCode() != HttpCode.SUCCESS){
    throw new RuntimeException("库存扣减失败");
}

 

可以看到,修改后的代码使用Fegin调用远程的用户微服务和商品微服务,已经完全没有了拼接URL路径的痕迹。

接下来,将io.binghe.shop.order.controller.OrderController类中的OrderService修改为注入beanName为orderServiceV5的OrderService对象,如下所示。

@Autowired
@Qualifier(value = "orderServiceV5")
private OrderService orderService;

至此,订单微服务的代码修改完成。

测试负载均衡效果
启动订单微服务,并在浏览器或其他测试工具中多次访问链接http://localhost:8080/order/submit_order?userId=1001&productId=1001&count=1,启动的每个用户微服务和商品微服务都会打印相关的日志,说明使用Ribbon实现了负载均衡功能。

注意:这里就不粘贴测试时每个启动的微服务打印的日志了,小伙伴们可自行测试并演示效果。

好了,至此,我们就用三种方式实现了微服务之间调用的负载均衡,限于篇幅,文中并未给出完整的源代码,想要完整源代码的小伙伴可加入【冰河技术】知识星球获取源码。

另外,一不小心就写了8章了,小伙伴们你们再不上车就跟不上了!!!

关于星球
最近,冰河创建了【冰河技术】知识星球,《SpringCloud Alibaba实战》专栏的源码获取方式会放到知识星期中,同时在微信上会创建专门的知识星球群,冰河会在知识星球上和星球群里解答球友的提问。

 

文章转自公众号:冰河技术

分类
已于2022-5-31 16:31:43修改
收藏
回复
举报
回复
    相关推荐