SpringCloud(5)Eureka与Ribbon -服务提供者与服务消费者--服务消费者consumer方式一
消费服务的三种方式:
通过DisconveryClient来调用,(我们这里用的这种)
通过LoadBalancerClient来调用
通过@LoadBalanced来
一:首先创建一个module
创建一个名字叫service-consumer的module(方式和prover一样)
二:pom文件和我们的prover一样,这里的yml修改
我们这里不将自己注册到服务列表中,只能拉取服务列表,从服务列表中远程调用服务
server: port: 9090 # 端口 spring: application: name: service-consumer # 应用名称 # 配置 Eureka Server 注册中心 eureka: client: register-with-eureka: false # 是否将自己注册到注册中心,默认为 true registry-fetch-interval-seconds: 10 # 表示 Eureka Client 间隔多久去服务器拉取注册信息,默认为30 秒 service-url: # 设置服务注册中心地址 defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
三:创建包,与俩个实体类
四:创建Service与impl
springboot与springcloud默认是没有RestTemplate的,我们需要在启动类中加上其Bean
package com.xxxx.service.impl; /** * 订单服务 */ @Service public class OrderServiceImpl implements OrderService { @Autowired RestTemplate restTemplate; // 元数据对象(它是去我们注册中心获取服务列表,获取多个服务 // ,然后我们需要从多个服务中通过名称来找到我们这个具体的服务 @Autowired private DiscoveryClient discoveryClient; @Override public order selectOrderById(Integer id) { return new order(id,"order-001","中国",319940D,selectProductListBydiscoveryClient()); } private List<product> selectProductListBydiscoveryClient(){ StringBuffer sb=null; //获取服务列表 List<String> serviceIds=discoveryClient.getServices(); if (CollectionUtils.isEmpty(serviceIds)) return null; //根据服务名称获取服务 List<ServiceInstance> serviceInstances=discoveryClient.getInstances("service-provider"); if (CollectionUtils.isEmpty(serviceInstances)) return null; ServiceInstance si=serviceInstances.get(0); sb=new StringBuffer(); sb.append("http://"+si.getHost()+":"+si.getPort()+"/product/list"); //ResponseEntity : 封装了返回数据 ResponseEntity<List<product>> response=restTemplate.exchange( sb.toString(), HttpMethod.GET, null, new ParameterizedTypeReference<List<product>>(){} ); return response.getBody(); } }
这里说一下远程调用的restTemplate中的方法:
二.RestTemplate使用 RestTemplate提供了六种常用的HTTP方法实现远程服务调用,RestTemplate的方法名遵循一定的命名规范,第一部分表示用哪种HTTP方法调用(get,post),第二部分表示返回类型。 getForObject – 发送GET请求,将HTTP response转换成一个指定的object对象 postForEntity – 发送POST请求,将给定的对象封装到HTTP请求体,返回类型是一个HttpEntity对象 每个HTTP方法对应的RestTemplate方法都有3种。其中2种的url参数为字符串,URI参数变量分别是Object数组和Map,第3种使用URI类型作为参数 exchange 和execute 方法比上面列出的其它方法(如getForObject、postForEntity等)使用范围更广,允许调用者指定HTTP请求的方法(GET、POST、PUT等),并且可以支持像HTTP PATCH(部分更新)。 这次主要讲的是exchange 方法的使用。 exchange(String url, HttpMethod method,@Nullable HttpEntity<?> requestEntity, Class responseType, Map 参数说明: url:请求路径 method:请求的方法(GET、POST、PUT等) requestEntity:HttpEntity对象,封装了请求头和请求体 responseType:返回数据类型 uriVariables:支持PathVariable类型的数据。 创建一个RestTemplate连接
五:Contorller层
六:启动Eureka8761与Eureka8763与,生产者prover ,启动consumer
通过consumer来远程调用我们的prover服务:
二:通过LoadBalancerClient来调用(运用负载均衡器)
修改一下我们的consumerServiceImpl中的类就可以了
package com.xxxx.service.impl; /** * 订单服务 */ @Service public class OrderServiceImpl implements OrderService { @Autowired RestTemplate restTemplate; // 元数据对象(它是去我们注册中心获取服务列表,获取多个服务 // ,然后我们需要从多个服务中通过名称来找到我们这个具体的服务 @Autowired private DiscoveryClient discoveryClient; //负载均衡器 Ribbon 负载均衡器 @Autowired private LoadBalancerClient loadBalancerClient; @Override public order selectOrderById(Integer id) { return new order(id,"order-001","中国",319940D,selectProductListBydiscoveryClient1()); } private List<product> selectProductListBydiscoveryClient(){ StringBuffer sb=null; //获取服务列表 List<String> serviceIds=discoveryClient.getServices(); if (CollectionUtils.isEmpty(serviceIds)) return null; //根据服务名称获取服务 List<ServiceInstance> serviceInstances=discoveryClient.getInstances("SERVICE-PRODUCT"); if (CollectionUtils.isEmpty(serviceInstances)) return null; ServiceInstance si=serviceInstances.get(0); sb=new StringBuffer(); sb.append("http://"+si.getHost()+":"+si.getPort()+"/product/list"); //ResponseEntity : 封装了返回数据 ResponseEntity<List<product>> response=restTemplate.exchange( sb.toString(), HttpMethod.GET, null, new ParameterizedTypeReference<List<product>>(){} ); return response.getBody(); } private List<product> selectProductListBydiscoveryClient1(){ StringBuffer sb=null; //获取服务列表 这里没有了获取服务列表 //根据服务名称获取服务 ServiceInstance si=loadBalancerClient.choose("SERVICE-PRODUCT"); if (si==null) return null; sb=new StringBuffer(); sb.append("http://"+si.getHost()+":"+si.getPort()+"/product/list"); //ResponseEntity : 封装了返回数据 ResponseEntity<List<product>> response=restTemplate.exchange( sb.toString(), HttpMethod.GET, null, new ParameterizedTypeReference<List<product>>(){} ); return response.getBody(); } }
三:通过@LoadBalanced来实现
启动类注入RestTemplate时添加@LoadBalanced负载均衡注解,表示这个RestTemplate在请求时拥有客户端负载均衡的能力
package com.xxxx; //@EnableEurekaClient //@EnableEurekaClient 注解,目前版本如果配置了Client注册中心,默认会开启该注解 @SpringBootApplication public class ServiceConsumerApplication { @Bean @LoadBalanced //负载均衡注解 public RestTemplate restTemplate(){ return new RestTemplate(); } public static void main( String[] args ) { SpringApplication.run(ServiceConsumerApplication.class,args); } }
package com.xxxx.service.impl; import java.util.List; /** * 订单服务 */ @Service public class OrderServiceImpl implements OrderService { @Autowired RestTemplate restTemplate; // 元数据对象(它是去我们注册中心获取服务列表,获取多个服务 // ,然后我们需要从多个服务中通过名称来找到我们这个具体的服务 @Autowired private DiscoveryClient discoveryClient; //负载均衡器 Ribbon 负载均衡器 @Autowired private LoadBalancerClient loadBalancerClient; @Override public order selectOrderById(Integer id) { return new order(id,"order-001","中国",319940D,selectProductListBydiscoveryClient3()); } private List<product> selectProductListBydiscoveryClient3(){ //ResponseEntity : 封装了返回数据 ResponseEntity<List<product>> response=restTemplate.exchange( "http://service-product/product/list", //这里只需要写微服务的应用名称就可以service-product HttpMethod.GET, null, new ParameterizedTypeReference<List<product>>(){}); return response.getBody(); } }