需求
假设我们有个场景:
Order-Center 需要采用随机算法调用产品中心 , 而采用轮询算法调用其他中心微服务
工程
java代码实现细粒度配置 (不推荐)
注意事项: PayCenterRibbonConfig,ProductCenterRibbonConfig不能被放在我们主启动类所在包以及子包下,不然就起不到细粒度配置
【支付中心对应的Ribbon访问策略】
package com.globalconfig; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RoundRobinRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author 小工匠 * @version 1.0 * @description: TODO * @date 2022/2/2 19:42 * @mark: show me the code , change the world */ @Configuration public class PayCenterRibbonConfig { @Bean public IRule roundRobinRule() { return new RoundRobinRule(); } }
【产品中心对应的Ribbon访问策略】
package com.globalconfig; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author 小工匠 * @version 1.0 * @description: TODO * @date 2022/2/2 19:45 * @mark: show me the code , change the world */ @Configuration public class ProductCenterRibbonConfig { @Bean public IRule randomRule() { return new RandomRule(); } }
【带有@LoadBalanced的RestTemplate】
package com.artisan.config; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; /** * @author 小工匠 * @version 1.0 * @description: TODO * @date 2022/2/2 15:47 * @mark: show me the code , change the world */ @Configuration public class WebConfig { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
【为每个服务分配 访问策略 】
package com.artisan.config; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.cloud.netflix.ribbon.RibbonClients; import org.springframework.context.annotation.Configuration; /** * @author 小工匠 * @version 1.0 * @description: TODO * @date 2022/2/2 19:51 * @mark: show me the code , change the world */ @Configuration @RibbonClients(value = { @RibbonClient(name = "artisan-product-center",configuration = com.globalconfig.ProductCenterRibbonConfig.class), @RibbonClient(name = "artisan-pay-center",configuration = com.globalconfig.PayCenterRibbonConfig.class) }) public class CustomRibbonConfig { }
【Controller 】
import com.artisan.common.entity.OrderInfo; import com.artisan.common.entity.PayInfo; import com.artisan.common.entity.ProductInfo; import com.artisan.common.vo.OrderAndPayVo; import com.artisan.common.vo.OrderVo; import com.artisan.mapper.OrderInfoMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; /** * @author 小工匠 * @version 1.0 * @description: TODO * @date 2022/2/2 03:20 * @mark: show me the code , change the world */ @RestController @Slf4j public class OrderInfoController { @Autowired private RestTemplate restTemplate; @Autowired private OrderInfoMapper orderInfoMapper; /** * 调用地址, 注册中心 地址 */ public static final String PRODUCT_URI = "http://artisan-product-center/selectProductInfoById/"; public static final String PAY_URI = "http://artisan-pay-center/selectPayInfoByOrderNo/"; @RequestMapping("/v2/selectOrderInfoById/{orderNo}") public Object selectOrderInfoById(@PathVariable("orderNo") String orderNo) { OrderInfo orderInfo = orderInfoMapper.selectOrderInfoById(orderNo); if (null == orderInfo) { return "根据orderNo:" + orderNo + "查询没有该订单"; } // 发起远程Http调用 ResponseEntity<ProductInfo> responseEntity = restTemplate.getForEntity(PRODUCT_URI + orderInfo.getProductNo(), ProductInfo.class); ProductInfo productInfo = responseEntity.getBody(); if (productInfo == null) { return "没有对应的商品"; } OrderVo orderVo = new OrderVo(); orderVo.setOrderNo(orderInfo.getOrderNo()); orderVo.setUserName(orderInfo.getUserName()); orderVo.setProductName(productInfo.getProductName()); orderVo.setProductNum(orderInfo.getProductCount()); return orderVo; } @RequestMapping("/getOrderAndPayInfoByOrderNo/{orderNo}") public Object getOrderAndPayInfoByOrderNo(@PathVariable("orderNo") String orderNo) { OrderInfo orderInfo = orderInfoMapper.selectOrderInfoById(orderNo); if (null == orderInfo) { return "根据orderNo:" + orderNo + "查询没有该订单"; } ResponseEntity<PayInfo> responseEntity = restTemplate.getForEntity(PAY_URI + orderInfo.getProductNo(), PayInfo.class); PayInfo payInfo = responseEntity.getBody(); if (payInfo == null) { return "没有对应的支付信息"; } OrderAndPayVo orderAndPayVo = new OrderAndPayVo(); orderAndPayVo.setOrderNo(orderNo); orderAndPayVo.setProductNo(orderInfo.getProductNo()); orderAndPayVo.setProductCount(orderInfo.getProductCount()); orderAndPayVo.setPayNo(payInfo.getPayNo()); orderAndPayVo.setPayTime(payInfo.getPayTime()); orderAndPayVo.setUserName(orderInfo.getUserName()); return orderAndPayVo; } }
可以看到,实现了我们最开始的需求 。
配置实现细粒度配置 (推荐)
接着上面的工程,首先屏蔽掉 CustomRibbonConfig
然后再 artisan-cloud-customcfg-ribbon-order 子模块的配置文件 application.yml
增加
#自定义Ribbon的细粒度配置 artisan-pay-center: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule artisan-product-center: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
然后启动多个Pay和Product服务进行测试
结果如下:
访问4次
访问 10次