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)
*/
}