概述
在第二篇文章SpringCloud服务调用之Feign中,我们介绍了SpringCloud中使用feign进行服务调用的案例。当时还介绍了feign是基于ribbon的。
这一篇,我们就来看看通过原生
的ribbon是怎么进行服务调用的。
官方文档:https://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-ribbon
Ribbon is a client side load balancer which gives you a lot of control over the behaviour of HTTP and TCP clients. Feign already uses Ribbon, so if you are using
@FeignClient
then this section also applies.
ribbon可以实现服务调用和负载均衡,而feign集成了ribbon。
也就是说:feign是基于ribbon的,ribbon的调用可以理解是SpringCloud原生的服务调用。
注:这一篇,我们基于上一篇SpringCloud服务注册之Consul中的consul来实现这么一个demo。
需要:consul、service-producer服务(引入consul)、service-consumer服务(引入consul和ribbon)
版本:SpringBoot 2.0.7.RELEASE与SpringCloud Finchely.RELEASE
一、service-producer
服务生产者与上一节相同,需要引入consul-discovery
:
1.8
Finchley.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-consul-discovery
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
配置文件:
server:
port: 8200
spring:
application:
name: service-producer
cloud:
consul:
host: localhost
port: 8500
discovery:
register: true
instance-id: ${spring.application.name}:${server.port}
service-name: ${spring.application.name}
port: ${server.port}
启动类添加@EnableDiscoveryClient
注解:
package com.example.serviceproducer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ServiceProducerApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceProducerApplication.class, args);
}
}
测试接口:
package com.example.serviceproducer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "producer")
public class HelloAction {
@GetMapping(value = "hello/{name}")
public String hello(@PathVariable String name) {
return "Hello " + name + ", this is response from hello by service-producer.";
}
}
启动服务后,测试一下:
二、service-consumer
服务消费者需要引入consul-discovery
和netflix-ribbon
:
1.8
Finchley.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-consul-discovery
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-netflix-ribbon
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
配置文件与service-producer基本相同:
server:
port: 8201
spring:
application:
name: service-consumer
cloud:
consul:
host: localhost
port: 8500
discovery:
register: true
service-name: ${spring.application.name}
instance-id: ${spring.application.name}:${server.port}
port: ${server.port}
同样在启动类上添加@EnableDiscoveryClient
注解。
下面就有所不同了,还需要注入一个RestTemplate
的Bean实例——这个类来自spring-boot-starter-web
包:
package com.example.serviceconsumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
public class ServiceConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceConsumerApplication.class, args);
}
/**
* 注入RestTemplate Bean并开启负载均衡
* @return
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
注:也可以不采用注入而在使用的时候直接new RestTemplate()
。
看一下我编写的测试接口:
package com.example.serviceconsumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping(value = "consumer")
public class ConsumerAction {
@Autowired
private RestTemplate restTemplate;
@GetMapping(value = "test")
public String test(String name) {
// 利用RestTemplate,直接请求对应的service-name/request
String producerRes = restTemplate.getForObject("http://service-producer/producer/hello/" + name, String.class);
String res = "service-consumer服务调用service-producer服务,hello接口返回数据:" + producerRes;
System.out.println(res);
return res;
}
}
上面的示例中,使用了restTemplate.getForObject("http://service-producer/producer/hello/" + name, String.class);
来调用服务service-producer
的路径为producer/hello/{name}
的接口。
扩展:ribbon/feign/http比较
与普通的HTTP请求比较:HTTP请求使用http://ip:port/path
的方式请求,而ribbon则使用http://service-name/path
的方式。
与feign请求比较:
@FeignClient(name = "service-provider")
public interface HelloRemote {
@GetMapping(value = "hello/{name}")
public String hello(@PathVariable("name") String name);
}
feign是使用@FeignClient
来声明式地声明一个与被调用服务接口相同的接口,然后直接调用这个接口。而ribbon是直接通过路径调用。
四、测试
启动service-consumer后,看一下consul:
测试consumer服务调用producer服务:
至此,基于ribbon进行服务调用的示例已经完成。具体可以参考下面地址的源码。
五、项目源码
https://github.com/laolunsi/spring-cloud-examples/tree/master/04-ServiceConsumeRibbon
参考
- 方志朋-服务消费者(rest+ribbon)(Finchley版)https://blog.csdn.net/forezp/article/details/81040946
欢迎大家关注我的公众号:猿生物语,搜索关键词或扫码: