SpringCloud简介 Ribbon Eureka 远程调用RestTemplate类 openfeign

〇、SpringCloud

0.区别于单体项目和soa架构,微服务架构每个服务独立,灵活。

  1. spring cloud是一个完整的微服务框架,springCloud包括三个体系:

spring cloud Netflix

spring cloud Alibaba

spring 其他

2.spring cloud 版本命名

早期以伦敦地铁名命名,后来采用年份命名。

3.spring cloud 涵盖有非常多的子框架,每个框架有属于自己的版本。学习阶段需要先了解每一个子框架的用法。每个spring cloud框架 对应的spring boot版本也不一样

这里采用H版本

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
    </parent>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR12</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>


一、Eureka

1.Eureka 分为 Eureka service服务器 和 Eureka client客户端

所有客户端都在 服务器中注册自己:

将自己的客户端主机名和ip端口号储存在服务器中,这个存储过程也可以使用redis完成。如果给客户端搭建集群,主机名一样。

当客户端需要远程调用其他客户端时,通过告知服务器客户端主机名获取多个ip及端口号

这时客户端拿到了一系列的ip及端口号。可以使用Ribbon计算出这次远程调用哪一个客户端。

2.搭建Eureka service服务器 配置文件

 <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

server:
  port: 8761
eureka:
  client:
    # 因为当前项目为服务,不需要向服务注册自己,默认为true
    register-with-eureka: false
    # 因为当前为非集群版eureka,所以不需要同步其他节点数据
    fetch-registry: false

3.搭建Eureka client服务器 配置文件

   <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

server:
  port: 9999
# 配置服务注册的名称
spring:
  application:
    name: application-client
#配置EureKaServer的地址 默认为 http://localhost:8761/eureka/
#eureka:
#  client:
#    service-url:
#      defaultZone: http://localhost:8761/eureka/

4.访问Eureka

①开启service项目;
② 客户端编写三个启动类,每次启动时更改端口号;主机名application-client
③访问Eureka服务器


二、Ribbon

Ribbon是负责负载均衡的springCloud Netflix 子框架。

在访问Eureka 拿到访问地址后,本客户端调用Ribbon通过算法计算出一个访问地址。

核心接口为 LoadBalancerClient

1.这里启动两个 主机名为application-service 的客户端。

2.用一个application-client的客户端通过Eureka拿到application-service主机地址

3.多次访问localhost:9999/demo

可以看到默认的负载均衡策略为轮循。



三、远程调用 RestTemplate类

0)RestTemplate是spring用于发送http请求的模板类。这里配置该对象:

@LoadBalanced 注解用于开启Robbin负载均衡策略。

RandomRule对象是负载均衡的算法,随机选择调用地址。

1)创建springboot的父项目 、公共项目

新建子项目commen

commen依赖:

<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version> <!-- 请使用最新的版本号 -->
            <scope>provided</scope>
</dependency>

2)服务器

服务器正常写增删改查的项目,这里测试就直接返回对应数据方便观察接口调用

java 复制代码
@RestController
public class MyController {
//    @Value("${server.port}")
    private int port = 8080;

    /**
     * 返回类型为集合,泛型为自定类型。
     */
    @RequestMapping("/returnUsers")
    public List<User> returnUsers(int nums){
        List<User> result = new ArrayList<>();
        for(int i = 0; i < nums; i++){
            result.add(new User(100 + i, "姓名-" + i, 20+i));
        }
        return result;
    }

    /**
     * 任意请求方式, 返回值类型是集合。相对复杂的Java类型。
     * @return
     */
    @RequestMapping("/returnList")
    public List<String> returnList(int nums){
        List<String> result = new ArrayList<>();
        for(int i = 0; i < nums; i++){
            result.add("返回结果 - " + i);
        }
        return result;
    }

    /**
     * 任意请求,传递路径地址参数
     * @param name
     * @param age
     * @return
     */
    @RequestMapping("/restfulParams/{name}/{age}")
    public String restfulParams(@PathVariable("name") String name,
                                @PathVariable int age){
        System.out.println("端口号: " + port + ", 任意请求方式,restful参数, name = " +
                name + " ; age = " + age);
        return "restful参数, name = " + name + " ; age = " + age;
    }


    /**
     * post请求,请求体传递参数。参数使用@RequestBody处理。
     */
    @PostMapping("/postBodyParams")
    public String postBodyParams(@RequestBody Map<String, String> params){
        System.out.println("端口号: " + port + " , post请求,有请求体参数, params = " +
                params);
        return "post请求,请求体参数, params = " + params;
    }

    /**
     * post请求,有参数
     */
    @PostMapping("/postWithParams")
    public String postWithParams(String name, int age){
        System.out.println("端口号: " + port + " , post请求,有参数, name = " +
                name + " ; age = " + age);
        return "post请求有参数 : name = " +
                name + " ; age = " + age;
    }

    /**
     * post请求,没有参数
     */
    @PostMapping("/postNoParams")
    public String postNoParams(){
        System.out.println("端口号: " + port + " , post请求,没有参数");
        return "post请求,没有参数";
    }

    /**
     * get请求,包含参数
     */
    @GetMapping("/getWithParams")
    public String getWithParams(String name, int age){
        System.out.println("端口号: " + port + " 。 get请求,有参数, name = "
                + name + " ; age = " + age);
        return "get请求,包含参数 : name = " + name + " ; age = " + age;
    }

    /**
     * get请求,没有参数
     * @return
     */
    @GetMapping("/getNoParams")
    public String getNoParams(){
        System.out.println("端口号:" + port + "。 get请求,无参数。");
        return "get请求,无参数。";
    }
}

服务器依赖:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.example</groupId>
            <artifactId>commen</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

3)客户端配置RestTemplate对象

客户端依赖:

java 复制代码
  <dependencies>
        <dependency>
            <artifactId>spring-boot-starter-web</artifactId>
            <groupId>org.springframework.boot</groupId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.example</groupId>
            <artifactId>commen</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

4)使用RestTemplate对象在客户端测试服务器方法的调用

①请求行携带键值对的几种形式

②post请求自定义请求头 请求体为键值对

③post请求 传输请求体为json格式

④post请求 自定义传输请求体为json格式

⑤ exchange()通用公式

java 复制代码
@SpringBootTest
public class RestTemplateTest {
    @Autowired
    private RestTemplate restTemplate;
    @Test
    public void test(){
        String forObject = restTemplate.getForObject("http://localhost:8080/getNoParams", String.class);
        System.out.println("forObject = " + forObject);
    }

    @Test
    public void test1(){
        String forObject1 = restTemplate.getForObject("http://localhost:8080/getWithParams?name=张三&age=20", String.class);
        String forObject2 = restTemplate.getForObject("http://localhost:8080/getWithParams?name={a}&age={b}", String.class,"战法",29);

        Map<String,Object>  map= new HashMap();
        map.put("x","阿森纳");
        map.put("y",20);
        String forObject3 = restTemplate.getForObject("http://localhost:8080/getWithParams?name={x}&age={y}", String.class,map);
        System.out.println("forObject1 = " + forObject1);
        System.out.println("forObject2 = " + forObject2);
        System.out.println("forObject3 = " + forObject3);
    }

    @Test
    public void testPost(){
        restTemplate.postForObject("http://localhost:8080/postNoParams",null,String.class);
    }

    @Test
    public void testPost1(){

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("content-type","application/x-www-form-urlencoded");

        MultiValueMap<String,Object> map = new LinkedMultiValueMap<>();
        map.add("name","埃德加");
        map.add("age","20");

        HttpEntity<MultiValueMap<String,Object>> entity = new HttpEntity<>(map,httpHeaders);
        String s = restTemplate.postForObject("http://localhost:8080/postWithParams", entity, String.class);
        String s1 = restTemplate.postForObject("http://localhost:8080/postWithParams?name=咋很难&age=29", entity, String.class);
        System.out.println("s = " + s);
        System.out.println("s1 = " + s1);
    }


    @Test
    public void testPost2(){
        Map<String,Object> map = new HashMap<>();
        map.put("name","绽放");
        map.put("age",29);
        restTemplate.postForObject("http://localhost:8080/postBodyParams",map,String.class);
    }

    @Test
    public void testPost3() throws JsonProcessingException {

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("content-type","application/json");

//        MultiValueMap<String,Object> map = new LinkedMultiValueMap<>();
        Map<String,Object> map = new HashMap<>();
        map.put("name","埃德加");
        map.put("age","20");
        ObjectMapper objectMapper = new ObjectMapper();
        String s1 = objectMapper.writeValueAsString(map);

        HttpEntity<String> entity = new HttpEntity<>(s1,httpHeaders);
        String s = restTemplate.postForObject("http://localhost:8080/postBodyParams", entity, String.class);
        System.out.println("s = " + s);
    }

    @Test
    public void testEvery(){
        ResponseEntity<List<User>> exchange = restTemplate.exchange("http://localhost:8080/returnUsers?nums=9",
                HttpMethod.GET,
                null,
                new ParameterizedTypeReference<List<User>>() {
                });
        System.out.println("exchange = " + exchange);
    }
}


四、openfeign

1)编写Feign接口:

1.将要调用服务主机的Controller中所有单元方法全部复制

2.创建Feign接口,并粘贴所有方法,改写为抽象方法

java 复制代码
@FeignClient("application-service")
public interface Feign {

    @RequestMapping("/returnUsers")
    public List<User> returnUsers(int nums);

    /**
     * 任意请求方式, 返回值类型是集合。相对复杂的Java类型。
     * @return
     */
    @RequestMapping("/returnList")
    public List<String> returnList(@RequestParam("nums") int nums);

    /**
     * 任意请求,传递路径地址参数
     * @param name
     * @param age
     * @return
     */
    @RequestMapping("/restfulParams/{name}/{age}")
    public String restfulParams(@PathVariable("name") String name,
                                @PathVariable("age") int age);


    /**
     * post请求,请求体传递参数。参数使用@RequestBody处理。
     */
    @PostMapping("/postBodyParams")
    public String postBodyParams(@RequestBody Map<String, String> params);
    /**
     * post请求,有参数
     */
    @PostMapping("/postWithParams")
    public String postWithParams(@RequestParam("name") String name,@RequestParam("age") int age);

    /**
     * post请求,没有参数
     */
    @PostMapping("/postNoParams")
    public String postNoParams();

    /**
     * get请求,包含参数
     */
    @GetMapping("/getWithParams")
    public String getWithParams(@RequestParam("name")String name,@RequestParam("age")int age);

    /**
     * get请求,没有参数
     * @return
     */
    @GetMapping("/getNoParams")
    public String getNoParams();
}

3.添加注解



2)开启Eureka service 及Eureka client主机application-service:



3)调用Feign接口:

相关推荐
Doker 多克5 小时前
IntelliJ IDEA Docker集成
spring cloud·docker·intellij-idea
Hello Dam5 小时前
面向微服务的Spring Cloud Gateway的集成解决方案:用户登录认证与访问控制
spring cloud·微服务·云原生·架构·gateway·登录验证·单点登录
筏镜11 小时前
调整docker bridge地址冲突,通过bip调整 bridge地址
java·docker·eureka
小马爱打代码13 小时前
SpringCloud(注册中心+OpenFeign+网关+配置中心+服务保护+分布式事务)
分布式·spring·spring cloud
小笨猪-15 小时前
统⼀服务⼊⼝-Gateway
java·spring cloud·微服务·gateway
岁月变迁呀18 小时前
Spring Cloud Gateway 源码
java·spring·spring cloud·gateway
岁月变迁呀1 天前
Eureka服务注册源码
spring cloud·eureka
阿髙1 天前
docker 软连接修改存储位置
java·docker·eureka
夏尔Gaesar1 天前
Failed to start Docker Application Container Engine
docker·容器·eureka