目的:将请求分发到其他功能相同的服务
我们只关注软件负载均衡
在客户端负载均衡中,所有的客户端节点都有一份自己要访问的服务端地址列表,这些列表统统都是从服务注册中心获取的
在服务端负载均衡中,客户端节点只知道单一服务代理的地址,服务代理则知道所有服务端的地址
Ribbon是Netflix开发的客户端负载均衡器,为Ribbon配置"服务提供者地址列表"后,Ribbon就可以基于某种"负载均衡策略算法",自动地帮助服务消费者去请求提供者
Ribbon默认为我们提供了很多负载均衡算法,例如轮询、随机等
github地址:https://github.com/Netflix/ribbon
默认实现
其他规则
@Bean public IRule myRule(){ //return new RoundRobinRule(); //return new RandomRule(); return new RetryRule();
}
针对服务定ribbon策略
provider.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
给所有服务定ribbon策略
ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
属性配置方式优先级高于Java代码。
ribbon.eureka.enabled=false
ribbon.listOfServers=localhost:80,localhost:81
为service-sms设置 请求的网络地址列表
Ribbon可以和服务注册中心Eureka一起工作,从服务注册中心获取服务端的地址信息,也可以在配置文件中使用listOfServers字段来设置服务端地址
依赖注入
@Bean // 开启负载均衡 @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); }
接下来便可以使用资源地址调用服务
String url ="http://provider/getHi"; String respStr = restTemplate.getForObject(url, String.class);
getForEntity方法的返回值是一个ResponseEntity,ResponseEntity是Spring对HTTP请求响应的封装,包括了几个重要的元素,如响应码、contentType、contentLength、响应消息体等。
200,Hi,[Content-Type:"text/plain;charset=UTF-8", Content-Length:"8", Date:"Fri, 10 Apr 2020 09:58:44 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]
调用方
String url ="http://provider/getMap"; ResponseEntity<Map> entity = restTemplate.getForEntity(url, Map.class); System.out.println("respStr: " + entity.getBody());
生产方
@GetMapping("/getMap") public Map<String, String> getMap() { HashMap<String, String> map = new HashMap<>(); map.put("name", "500"); return map; }
调用方
ResponseEntity<Person> entity = restTemplate.getForEntity(url, Person.class); System.out.println("respStr:" + ToStringBuilder.reflectionToString(entity.getBody()));
生产方
@GetMapping("/getObj") public Person getObj() { Person person = new Person(); person.setId(100); person.setName("xiaoming"); return person; }
private int id; private String name;
传参调用
使用占位符
String url ="http://provider/getObjParam?name={1}"; ResponseEntity<Person> entity = restTemplate.getForEntity(url, Person.class,"hehehe...");
使用map
String url ="http://provider/getObjParam?name={name}"; Map<String, String> map = Collections.singletonMap("name", " memeda"); ResponseEntity<Person> entity = restTemplate.getForEntity(url, Person.class,map);
返回对象
Person person = restTemplate.getForObject(url, Person.class,map);
调用方
String url ="http://provider/postParam"; Map<String, String> map = Collections.singletonMap("name", " memeda"); ResponseEntity<Person> entity = restTemplate.postForEntity(url, map, Person.class);
生产方
@PostMapping("/postParam") public Person postParam(@RequestBody String name) { System.out.println("name:" + name); Person person = new Person(); person.setId(100); person.setName("xiaoming" + name); return person; }
调用方
String url ="http://provider/postParam"; Map<String, String> map = Collections.singletonMap("name", " memeda"); URI location = restTemplate.postForLocation(url, map, Person.class); System.out.println(location);
生产方
需要设置头信息,不然返回的是null
public URI postParam(@RequestBody Person person,HttpServletResponse response) throws Exception { URI uri = new URI("https://www.baidu.com/s?wd="+person.getName()); response.addHeader("Location", uri.toString());
可以自定义http请求的头信息,同时保护get和post方法
拦截器
需要实现`ClientHttpRequestInterceptor`接口
public class LoggingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { System.out.println("拦截啦!!!"); System.out.println(request.getURI()); ClientHttpResponse response = execution.execute(request, body); System.out.println(response.getHeaders()); return response; }
}
添加到resttemplate中
@Bean @LoadBalanced RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); restTemplate.getInterceptors().add(new LoggingClientHttpRequestInterceptor()); return restTemplate; }
原文:https://www.cnblogs.com/YC-L/p/14405562.html