Spring Cloud 细节(二)

五、Eureka的细节

  • 服务的注册:

    服务把自己的元数据注册到注册中心上,服务会每30秒向注册中心发一次心跳,进行服务续约。

  • 服务的剔除:

    注册中心每隔60秒,检查本地的地址列表中有没有超过90秒没有续约的服务,进行剔除。

  • 自我保护:

    如果注册中心发现服务比例(15分钟低于85%在线),那么注册中心就认为当前很有可能会出现误删的情况,于是自我保护就开启了。

六、Ribbon的细节

1.Ribbon中的负载均衡

ribbon的负载均衡策略有多种

默认的负载均衡策略是:roundrobin 轮询策略

  • RoundRobin: 轮询
  • Random:随机
  • WeightedResponseTime: 以响应时间为权重
  • Retry:如果在访问第一台不成功后会进行重试

如何修改负载均衡策略,在ribbon的配置类中提供IRule的bean即可

package com.qf.my.product.service.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.WeightedResponseTimeRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RibbonConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    @Bean
    public IRule getRule(){
        return new RandomRule();//随机的负载均衡策略
//        new WeightedResponseTimeRule(); 根据响应时间为权重的负载均衡策略
    }

}

2.Ribbon是如何进行负载均衡的?

七、RestTemplate详解

RestTemplate是Spring封装的一个用来进行Http通信的工具。之前的工具:

  • URLConnection:偏底层,需要加上自己的封装

  • HttpClient:Apache孵化项目,需要引入第三方来实现

  • OkHttp:第三方

1.Http协议包含的部分

  • 请求
    • 请求头
    • 请求行
    • 请求体
  • 响应- HttpEntity- ResponseEntity
    • 响应头
    • 响应行
    • 响应体

2. RestTemplate发送Get请求

1)getForEntity

getForEntity返回的是ResponseEntity对象,该对象中封装了响应消息头、响应消息行、响应消息体。

  • 重载方法一(String url, Class Response)

直接把携带的请求参数写在url后面

 ResponseEntity<User> entity = restTemplate.getForEntity("http://user-service/getUser/1/xiaoming", User.class);
        //entity是封装了响应消息的,获取的消息体
        User user = entity.getBody();

服务提供者如何接收参数:

@GetMapping("/getUser/{id}/{name}")
    public User getUser(@PathVariable Long id,@PathVariable String name){
        User user = new User();
        user.setId(id);
        user.setName(name);
        return user;
    }

用数组来封装请求参数

ResponseEntity<User> entity = restTemplate.getForEntity("http://user-service/getUserByVP?id={1}&name={2}", User.class,
                new Object[]{id, name});
        User body = entity.getBody();
        return body;

服务提供者如何接收参数

@GetMapping("/getUserByVP")
    public User getUserByVP(@RequestParam Long id,@RequestParam String name){
        User user = new User();
        user.setId(id);
        user.setName(name);
        return user;
    }

用map来封装请求参数

@Override
    public User getUserByMap(Long id,String name){
        Map<String,Object> map = new HashMap<>();
        map.put("id",id);
        map.put("name",name);
        ResponseEntity<User> entity = restTemplate.getForEntity("http://user-service/getUserByMap?id={id}&name={name}", User.class,
                map);
        return entity.getBody();
    }

服务提供者接收参数

  @GetMapping("/getUserByMap")
    public User getUserByMap(@RequestParam Long id,@RequestParam String name){
        User user = new User();
        user.setId(id);
        user.setName(name);
        return user;
    }

2) getForObject

getForObject和getForEntity的底层逻辑是一样的,只不过getForObject是直接获取响应消息体中的内容。而getForEntity是获取了整个响应消息(头、行、体)。

User user = restTemplate.getForObject("http://user-service/getUserByMap?id={id}&name={name}", User.class,map);

3.RestTemplate的Post请求

restTemplate的post请求比get请求多了一个request参数,这个request参数可以用来封装请求消息头和请求消息体的内容。

@Override
    public String addUser(User user) {
        ResponseEntity<String> entity = restTemplate.postForEntity("http://user-service/addUser", user, String.class);
        return entity.getBody();
    }

服务提供者的内容:

@PostMapping("/addUser")
    public String addUser(@RequestBody User user){
        if(Objects.nonNull(user)){
            return "success";
        }
        return "error";
    }
  • 重载方法二:第二个参数使用HttpEntity

HttpEntity可以封装请求头和请求体两部分内容,我们经常需要把Cookie放到请求头中传递到下游。

情况一:

传递的请求体中的内容是键值对,而不是具体的Java对象

服务消费者端:

 @Override
    public String addUserWithHeader(Long id, String name) {
        //封装Http的请求消息头
        HttpHeaders headers = new HttpHeaders();
      	//因为传递的是键值对,不需要使用json,下游使用@RequestParam来接参,所以需要设置成如下的mime类型
        headers.add("Content-Type","application/x-www-form-urlencoded");
        headers.add("myname","xiaoming");
        List<String> cook_list = new ArrayList<>();
        cook_list.add("login_token="+ UUID.randomUUID().toString().replaceAll("-",""));
        cook_list.add("cart_token="+ UUID.randomUUID().toString().replaceAll("-",""));
        headers.put(HttpHeaders.COOKIE,cook_list);//Cookie  login_token=sdfsdfsdf;cart_token=1wlkwekrjwer
        //封装请求消息体
        MultiValueMap<String,Object> map = new LinkedMultiValueMap<>();
        map.add("id",id);
        map.add("name",name);

        HttpEntity<Map> entity = new HttpEntity<>(map,headers);

        restTemplate.postForEntity("http://user-service/addUserWithHeader",entity,String.class);

        return null;
    }

服务提供者端:

@PostMapping("/addUserWithHeader")
    public String addUserWithHeader(@RequestParam Long id, @RequestParam String name,@CookieValue(name = "login_token") String login_token,
                                    @CookieValue(name="cart_token") String cart_token){
        System.out.println("name:"+name);
        System.out.println("login_token:"+login_token);
        System.out.println("cart_token:"+cart_token);

        return "success";
    }

情况二:

传递参数是具体的Java对象,需要把java对象以json字符串的形式进行传递

服务消费者端:

 @Override
    public String addUserWithHeader(Long id, String name) {
        //封装Http的请求消息头
        HttpHeaders headers = new HttpHeaders();
        //java对象以json形式传递
        headers.add("Content-Type","application/json");
        headers.add("myname","xiaoming");
        List<String> cook_list = new ArrayList<>();
        cook_list.add("login_token="+ UUID.randomUUID().toString().replaceAll("-",""));
        cook_list.add("cart_token="+ UUID.randomUUID().toString().replaceAll("-",""));
        headers.put(HttpHeaders.COOKIE,cook_list);//Cookie  login_token=sdfsdfsdf;cart_token=1wlkwekrjwer
        //封装请求消息体
        User user = new User();
        user.setId(1001L);
        user.setName("xiaohong");
        HttpEntity<User> entity = new HttpEntity<>(user,headers);

        restTemplate.postForEntity("http://user-service/addUserWithHeader",entity,String.class);

        return null;
    }

服务提供者端:

    @PostMapping("/addUserWithHeader")
    public String addUserWithHeader(@RequestBody User user,@CookieValue(name = "login_token") String login_token,
                                    @CookieValue(name="cart_token") String cart_token){
        System.out.println(user.getName());
        System.out.println("login_token:"+login_token);
        System.out.println("cart_token:"+cart_token);

        return "success";
    }

注意:postForObject和getForObject是一个意思,直接获得响应体中的内容。

posted @ 2021-07-21 21:55  牛奶配苦瓜  阅读(38)  评论(0编辑  收藏  举报