在微服务架构中,最常见的场景就是微服务之间的相互调用。比如,用户微服务调用订单微服务发起一个下单的请求,在进行保存订单之前,需要调用商品微服务查询商品的信息。我们把调用方称为服务消费者,把请求的接收者称为服务提供者
getForObject
postForObject
getForEntity
ResponseEntity<T>
,
ResponseEntity<T>
是Spring对HTTP请求响应的封装,
包括了几个重要的元素,如响应码、contentType、contentLength、响应消息体等。postForEntity
exchange
ResponseEntity<String> results = restTemplate.exchange(url,HttpMethod.GET, null, String.class, params);
/**
说明:1)url: 请求地址;
2)method: 请求类型(如:POST,PUT,DELETE,GET);
3)requestEntity: 请求实体,封装请求头,请求内容
4)responseType: 响应类型,根据服务接口的返回类型决定
5)uriVariables: url中参数变量值
*/
RestTemplate可以实现微服务之间的相互调用,但是RestTemplate有一定的问题:
解决方案:Ribbon
Ribbon是NetFlix的一个负载均衡器,例外它还可以同样使用RestTemplate完成对微服务之间的调用
你可以认为:Ribbon就是在RestTemplate的基础之上,提供了负载均衡的能力
Ribbon一般是配合Eureka注册中心来使用,意味着:Ribbon可以从Eureka中去发现自己需要的微服务实例
Ribbon提供的这种负载均衡的原理,是一种客户端的负载均衡机制
负载均衡:将负载(HTTP的请求)较为平均的分配到服务器上去
负载均衡常见的算法:轮询,权重,IP地址黏贴,最少连接
负载均衡的分类
在调用的一方,开启负载均衡
配置Ribbon实际上就是开启它的负载均衡
说Ribbon的底层就是RestTemplate,那么配置Ribbon实际上就是在配置RestTemplate
//在产生RestTemplate实例时,使用@LoadBalanced注解,那么RestTemplate就拥有了负载均衡的能力
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
public String getUrl(){
// 将之前的return "http://127.0.0.1:9091/"中
// 127.0.0.1:9091替换成 micro-base-server(被调用者的spring.application.name)
return "http://micro-base-server/";
}
com.netflix.loadbalancer.RoundRobinRule
com.netflix.loadbalancer.RandomRule
com.netflix.loadbalancer.RetryRul
com.netflix.loadbalancer.WeightedResponseTimeRule
com.netflix.loadbalancer.BestAvailableRule
com.netflix.loadbalancer.AvailabilityFilteringRule
在配置类中进行定义
@Configuration
public class loadbanlancerConfig {
@Bean
public IRule myRandomRule() {
return new RandomRule();
}
}
#ribbon的全局时间配置
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RetryRule
ConnectTimeout: 250 #Ribbon的连接超时时间(毫秒),默认1秒
ReadTimeout: 1000 #Ribbon的数据读取超时时间,默认1秒
OkToRetryOnAllOperations: true #是否对所有操作都进行重试
MaxAutoRetriesNextServer: 1 #切换实例的重试次数
MaxAutoRetries: 1 #对当前实例的重试次数
star-orders: #微服务的名称
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RetryRule
ConnectTimeout: 250 #Ribbon的连接超时时间(毫秒),默认1秒
ReadTimeout: 1000 #Ribbon的数据读取超时时间,默认1秒
OkToRetryOnAllOperations: true #是否对所有操作都进行重试
MaxAutoRetriesNextServer: 1 #切换实例的重试次数
MaxAutoRetries: 1 #对当前实例的重试次数
当全局配置和局部配置,同时存在时将以 “局部配置为主”
RestTemplate ,Ribbon都存在这么一个问题:代码耦合度很高。OpenFeign,它就是一种典型的接口式编程方案,从而可以做到微服务之间相互调用时,松散耦合关系
Feign是Netflix开发的声明式,模板化的HTTP客户端
Feign可帮助我们更加便捷,优雅的调用HTTP API
在Spring Cloud中,使用Feign非常简单——创建一个接口,并在接口上添加一些注解,代码就完成了。
Spring Cloud对Feign进行了增强,使Feign支持了Spring MVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便
OpenFeign实际上就是对Ribbon接口化封装,所以feign的负载均衡和时间配置,也是和ribbon一样的
避坑:使用Feign,如果消费端传递对象类型的参数,那么服务端必须使用@RequestBody
接参
<!-- OpenFeign的调用插件 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在启动类上,添加@EnableFeignClients
,开启对OpenFeign的支持
@EnableFeignClients
@EnableEurekaClient
@SpringBootApplication
public class MicroUserServerApplication {
public static void main(String[] args) {
SpringApplication.run(MicroUserServerApplication.class, args);
}
}
//@FeignClient的value属性,定义了服务生产方的spring.application.name名称
@FeignClient("star-product")
public interface ProductServerFeign {
//无参get请求
@GetMapping("/product/findAllProduct")
ResultVO findAllProduct();
//有参get请求,这种方法需要使用注解@PathVariable来声明参数位置
@GetMapping("/product/findByPid/{pid}")
ResultVO findByPid(@PathVariable("pid") Integer pid);
//有参post请求,这种方法需要在feign和提供者中使用@RequestBody来传参
@PostMapping("/product/save")
ResultVO save(@RequestBody Product product);
}
@Autowired
private ProductServerFeign productServerFeign;
@GetMapping("/findAllProduct")
public ResultVO findAllProduct(){
ResultVO resultVO = productServerFeign.findAllProduct();
return resultVO;
}
@GetMapping("/findByPid/{pid}")
public ResultVO findByPid(@PathVariable("pid") Integer pid){
ResultVO resultVO = productServerFeign.findByPid();
return resultVO;
}
@PostMapping("/save")
public ResultVO save(Product product){
ResultVO resultVO = productServerFeign.save(product);
return resultVO;
}
Feign提供了日志打印功能,我们可以通过配置来调整日志级别,可以让我们程序员查看Feign中Http请求的细节
开发环境以及测试环境,可以将Feign日志功能开启,但是生产环境下,请将日志功能关闭
日志级别
具体配置
feign:
client:
config:
micro-base-server: #被调用者的微服务名称
loggerLevel: FULL
logging:
level:
root: info #将日志下调至Debug
top.ygang.microuserserver.classdemo.openFeign.MicroBaseServerFeign: debug