SpringBoot26 利用 Ribbon + RestTemplate 调用远程服务资源
1 RestTemplate扫盲
借助 RestTemplate,Spring应用能够方便地使用REST资源
2 准备
创建三个springCloud项目
》Eureaka : 服务注册中心
》Product 商品服务
》Order 订单服务
技巧01:Eureaka 项目需要引入 spring-cloud-starter-netflix-eureka-server 依赖;其余两个项目需要引入 spring-cloud-starter-netflix-eureka-client 依赖
技巧02:order 服务需要调用 product 项目中的资源数据【请求url为:http://127.0.0.1:8080/msg】,我们可以利用 RestTemplate 来实现
坑01:所有的 springCloud项目中设置 eureka.instance.hostname 配置时需要注意,因为这个配置必须是IP地址或者域名;因为利用LoadBalancerClient根据应用名获取到的数据就是这个配置
坑02:直接利用RestTemplate实现时是古老的方式实现,而且如果远程服务是集群部署时需要自己实现负载均衡的逻辑
3 RestTemplate的三种使用方式
3.1 直接将url写死
》创建 RestTemplate 实例 restTemplate
》调用 restTemplate 的 getForObject 方法获取数据
技巧01:getForObject 第一个参数接受一个string类型的url,例如:http://127.0.0.1:8080/msg;第二个参数指定响应数据类型
技巧02:这是古老的方式实现,需要自己实现负载均衡和远程服务的信息配置
RestTemplate restTemplate = new RestTemplate(); String response = restTemplate.getForObject("http://127.0.0.1:8080/msg", String.class);
3.2 利用 LoadBalancerClient 获取引用IP和应用端口
技巧02:利用ribbon获取远程服务信息,而且ribbon还实现了负载均衡功能
》依赖注入 LoadBalancerClient 实例 loadBalancerClient
@Autowired private LoadBalancerClient loadBalancerClient;
》调用 loadBalancerClient 的 choose 方法获取应用服务实例 serviceInstance
》调用 serviceInstance 的 getHost 方法获取应用服务IP
【技巧01:如果应用服务设置了eureka.instance.hostname,那么getHost 方法返回就是eureka.instance.hostname的配置值】
》调用 serviceInstance 的 getPort 方法获取应用服务端口
》将获取到的IP和端口以及请求路径拼接成请求资源的url即可,例如:http://127.0.0.1:8080/msg
》在调用 RestTemplate 实例的 getForObject 方法
3.3 通过配置实现
利用了@LoadBalanced,可以在restTemplate中使用应用名
》创建一个配置类
package cn.xiangxu.order.config; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; /** * @author 王杨帅 * @create 2018-07-24 21:37 * @desc RestConfig配置类 **/ @Component public class RestTemplateConfig { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
》依赖注入 RestTemplate 实例 restTemplate
@Autowired private RestTemplate restTemplate;
》调用 restTemplate 的 getForObject 方法获取数据
【技巧01:这时候可以直接利用应用服务名称来代替应用IP和应用端口信息,例如:"http://PRODUCT/msg"】
3.4 代码汇总
package cn.xiangxu.product.controller; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.annotations.Select; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * @author 王杨帅 * @create 2018-07-24 20:45 * @desc 服务端控制层 **/ @RestController @Slf4j public class ServerController { @GetMapping(value = "/msg") public String msg() { String result = "商品微服务中的信息"; log.info(result); return result; } }
package cn.xiangxu.order.config; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; /** * @author 王杨帅 * @create 2018-07-24 21:37 * @desc RestConfig配置类 **/ @Component public class RestTemplateConfig { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
package cn.xiangxu.order.controller; import cn.xiangxu.order.config.RestTemplateConfig; import com.netflix.discovery.converters.Auto; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; /** * @author 王杨帅 * @create 2018-07-24 20:51 * @desc 客户端控制层 **/ @RestController @Slf4j public class ClientController { // @Autowired // private LoadBalancerClient loadBalancerClient; @Autowired private RestTemplate restTemplate; @GetMapping("/getProductMsg") public String getProductMsg() { // 方式01 直接将url写死 // RestTemplate restTemplate = new RestTemplate(); // String response = restTemplate.getForObject("http://127.0.0.1:8080/msg", String.class); // 方式02:利用LoadBalancerClient获取应用名(IP)和端口,在组装成url // RestTemplate restTemplate = new RestTemplate(); // ServiceInstance serviceInstance = loadBalancerClient.choose("PRODUCT"); // log.info(serviceInstance.getHost()); // log.info(serviceInstance.getPort() + ""); // String url = String.format("http://%s:%s", serviceInstance.getHost(), serviceInstance.getPort() + "/msg"); // String response = restTemplate.getForObject(url, String.class); // 方式03:通过配置实现,利用了@LoadBalanced,可以在restTemplate中使用应用名 String response = restTemplate.getForObject("http://PRODUCT/msg", String.class); log.info(response); return response; // return null; } }