Spring Cloud Ribbon是一个基于http和tcp的客户端负载均衡工具,基于Netflix Ribbon实现。Spring Cloud Ribbon虽然是Spring cloud的一个组件,但不需要像注册中心,配置中心等独立部署,它几乎存在于每一个spring cloud构建的微服务中。
负载均衡是系统架构中一个非常重要的内容,它是对系统进行高可用,缓解网络压力和处理能力扩容的重要手段。服务端负载均衡一般使用硬件设备或者nginx实现。在spring cloud中,客户端负载均衡需要配合注册中心实现,。
关于Ribbon,重要的是RestTemplate对象的使用。通过RestTemplate,配合注册中心,可以很容易地实现不同服务之间的数据交互(须在同一个或一组注册中心下)。
下面的两个服务已经分别向同一个Eureka服务端注册,具体参见上一篇博客。
1.涉及到的实体类:
public class Data {
private String id;
private String name;
private Integer age;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
public class User {
private String id;
private String name;
private Integer age;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
这两个类属性的名称是相同的,一个对应于服务提供者,一个对应于服务消费者。
2.服务提供者
@RestController
public class HelloController {
@RequestMapping(value = "/getUserForEntity",method = RequestMethod.GET)
public User getUserForEntity(User user){
return user;
}
/**
* post接口
* @param @RequestBody 注解必须有
* @return
*/
@RequestMapping(value = "/postUserForEntity",method=RequestMethod.POST)
public User postUserForEntity(@RequestBody User user){
if(!StringUtils.isEmpty(user.getId())){
user.setId(user.getId()+"_post");
}
if(!StringUtils.isEmpty(user.getName())){
user.setName(user.getName()+"_post");
}
return user;
}
/**
* post接口
*/
@RequestMapping(value = "/postUserForEntity2",method=RequestMethod.POST)
public User postUserForEntity2(@RequestBody User user,String mingzi){
if(!StringUtils.isEmpty(mingzi)){
user.setName(mingzi);
}
return user;
}
/**
* put接口
* @param
*/
@RequestMapping(value = "/putUser",method=RequestMethod.PUT)
public void putUser( @RequestBody User user){
System.err.println(user);
//输出:User{id='null', name='null', age=13}
}
}
服务提供者的服务名为“HELLO-SERVICE”
3.服务消费者,Ribbon
@RestController
public class ConsumerController {
@Resource
private RestTemplate restTemplate;
@RequestMapping(value = "ribbon-consumer",method = RequestMethod.GET)
public String helloConsumer(){
//HELLO-SERVICE
return restTemplate.getForEntity("http://HELLO-SERVICE/hello",String.class).getBody();
}
/**
* 请求get类型的接口,占位符形式
* @param name
* @return
*/
@RequestMapping(value = "getUser1",method = RequestMethod.GET)
public Data getUser1(String name){
//第一个参数为请求接口的url,用占位符的方式定义get请求附带的参数,第二个参数为要返回的数据类型,最后一个参数为占位符的具体值
ResponseEntity<Data> entity=restTemplate.getForEntity("http://HELLO-SERVICE/getUserForEntity?name={1}",Data.class,name);
return entity.getBody();
}
/**
* 请求get类型的接口,map形式
* @param age
* @return
*/
@RequestMapping(value = "getUser2",method = RequestMethod.GET)
public Data getUser2(Integer age){
Map<String,Integer>map=new HashMap<>();
map.put("age",age);
//第一个参数为请求的url,第二个参数为要返回的数据类型,第三个参数为请求参数,使用map方式
ResponseEntity<Data> entity=restTemplate.getForEntity("http://HELLO-SERVICE/getUserForEntity?age={age}",Data.class,map);
return entity.getBody();
}
/**
* 请求get类型的接口,URI形式(URI是java.net包下的一个类,表示统一资源标示符)
* @param id
* @return
*/
@RequestMapping(value = "getUser3",method = RequestMethod.GET)
public Data getUser3(String id,String name){
/**
* expand(...)方法可以传入多个参数
*/
UriComponents uriComponents= UriComponentsBuilder.fromUriString("http://HELLO-SERVICE/getUserForEntity?id={id}&name={name}")
.build()
.expand(id,name)
.encode();
URI uri=uriComponents.toUri();
//第一个参数为uri,第二个参数为响应内容的类型定义
ResponseEntity<Data> entity=restTemplate.getForEntity(uri,Data.class);
return entity.getBody();
}
/**
* 对getForEntity的进一步封装,直接返回包装好的对象
* 下面是这三个方法的重载
*
* getForObject(String url, Class responseType, Object... variables)
* getForObject(String url, Class responseType, Map variables)
* getForObject(URI uri, Class variables)
*
*/
/**
* 请求post类型的接口
* @return 接口响应的数据
*/
@RequestMapping(value = "postUser1",method = RequestMethod.GET)
public Data postUser1(){
Data data=new Data();data.setAge(42); data.setName("张飞");
/**
* 第一个参数是访问接口的地址,第二个参数为提交的body内容,第三个参数是请求响应返回的body类型
*/
ResponseEntity<Data> entity=restTemplate.postForEntity("http://HELLO-SERVICE/postUserForEntity",data,Data.class);
return entity.getBody();
}
/**
*
* @param mingzi
* @return
*/
@RequestMapping(value = "postUser2",method = RequestMethod.GET)
public Data postUser2(String mingzi){
Data data=new Data();data.setAge(22);
/**
* 在post请求的url中附带了get请求参数
*/
ResponseEntity<Data> entity=restTemplate.postForEntity("http://HELLO-SERVICE/postUserForEntity2?mingzi={1}",data,Data.class,mingzi);
return entity.getBody();
//返回结果:{"id":null,"name":"lisi","age":22}
}
/**
* 其他两种形式,和get请求比较类似
*
* postForEntity(String url, Object request, Class responseType, Map variables)
* postForEntity(URI var1, Object request, Class responseType)
*
*/
/**
* postForObject方法的三种重载,直接将请求响应的body内容包装成对象
*
* postForObject(String url, Object request, Class responseType, Object... variables)
* postForObject(String url, Object request, Class responseType, Map variables)
* postForObject(URI uri, Object request, Class variables)
*/
/**
* post 方式提交资源,并返回资源的URI,下面是三种方法的重载:
* URI
* postForLocation(String url, Object request, Object... variables)
* postForLocation(String url, Object request, Map variables)
* postForLocation(URI url, Object request)
*/
/**
* put请求,put方法为void类型,没有返回内容
*/
@RequestMapping(value = "putUser",method = RequestMethod.GET)
public void putUser(){
Data data=new Data();data.setAge(13);
restTemplate.put("http://HELLO-SERVICE/putUser",data);
}
/**
* put方法的三种重载方式
* put(String url, Object request, Object... variables)
* put(String url, Object request, Map variables)
* put(URI uri, Object variables)
*/
/**
* delete(String url, Object... variables)
* delete(String url, Map variables)
* delete(URI uri)
*/
}