假设我们有个场景:
Order-Center 需要采用随机算法调用产品中心 , 而采用轮询算法调用其他中心微服务
注意事项: 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次