SpringCloud-Eureka与生产者消费者

微信公众号:[0error] 关注可了解更多的知识干货,也可看看生活杂谈。如有问题或建议,欢迎在公众号留言。

今天继续学习SpringCloud。

上篇我们讲了微服务的概念

这一篇针对如何在Eureka上注册服务,消费者如何消费详细说说

以下代码皆用最简单的代码示例,并非真正的业务代码

学习中用到的学习资料如下:

文章:SpringCloud极简入门

https://gitbook.cn/gitchat/column/5e38e68dec8d9033cf91a047

视频:Spring Cloud从入门到实战

https://www.bilibili.com/video/BV1p4411K7pz?spm_id_from=333.999.0.0


Eureka分为两部分

  • Eureka Server,注册中心
  • Eureka Client,所有要进行注册的微服务通过 Eureka Client 连接到 Eureka Server,完成注册。

Eureka Server代码实现

  • 创建父工程,pom.xml
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.0.7.RELEASE</version>
</parent>
 
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
</dependencies>
 
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>Finchley.SR2</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
  • 在父工程下创建 Module,pom.xml
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    <version>2.0.2.RELEASE</version>
  </dependency>
</dependencies>
  • 创建配置文件 application.yml,添加 Eureka Server 相关配置。
server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8761/eureka/

属性说明

server.port:当前 Eureka Server 服务端口。

eureka.client.register-with-eureka:是否将当前的 Eureka Server 服务作为客户端进行注册。

eureka.client.fetch-fegistry:是否获取其他 Eureka Server 服务的数据。

eureka.client.service-url.defaultZone:注册中心的访问地址。

  • 创建启动类
package com.janeroad;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class,args);
    }
}

注解说明:

@SpringBootApplication:声明该类是 Spring Boot 服务的入口。

@EnableEurekaServer:声明该类是一个 Eureka Server 微服务,提供服务注册和服务发现功能,即注册中心。

打开浏览器,访问 http://localhost:8761,可看到如下界面,注册中心启动成功

SpringCloud-Eureka与生产者消费者

服务提供者代码实现

分布式系统架构中的所有微服务都需要在注册中心完成注册才能被发现进而使用,服务提供者和服务消费者是从业务角度来划分的,实际上服务提供者服务消费者都是通过 Eureka Client 连接到 Eureka Server 完成注册,现在实现一个服务提供者,并且在 Eureka Server 完成注册,大致思路是先通过 Spring Boot 搭建一个微服务应用,再通过 Eureka Client 将其注册到 Eureka Server,创建 Eureka Client 的过程与创建 Eureka Server 十分相似。

  • 创建 Module ,pom.xml
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>2.0.2.RELEASE</version>
    </dependency>
</dependencies>
  • 创建配置文件 application.yml,添加 Eureka Client 相关配置
server:
  port: 8010
spring:
  application:
    name: provider
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

属性说明:

spring.application.name:当前服务注册在 Eureka Server 上的名称。

eureka.client.service-url.defaultZone:注册中心的访问地址。

eureka.instance.prefer-ip-address:是否将当前服务的 IP 注册到 Eureka Server。

  • 创建启动类
package com.janeroad;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }
}
  • 实体类
package com.janeroad.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private long id;
    private String name;
    private int age;
}
  • Repository
package com.janeroad.repository;

import com.janeroad.entity.Student;

import java.util.Collection;

public interface StudentRepository {
    public Collection findAll();
    public Student findById(long id);
    public void saveOrUpdate(Student student);
    public void deleteById(long id);
}
  • RepositoryImpl
package com.janeroad.repository.impl;

import com.janeroad.entity.Student;
import com.janeroad.repository.StudentRepository;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

@Repository
public class StudentRepositoryImpl implements StudentRepository {
    private static Map studentMap;
    static {
        studentMap = new HashMap<>();
        studentMap.put(1L,new Student(1L,"张三",22));
        studentMap.put(2L,new Student(2L,"李四",23));
        studentMap.put(3L,new Student(3L,"王五",24));
    }

    @Override
    public Collection findAll() {
        return studentMap.values();
    }

    @Override
    public Student findById(long id) {
        return studentMap.get(id);
    }

    @Override
    public void saveOrUpdate(Student student) {
        studentMap.put(student.getId(),student);
    }

    @Override
    public void deleteById(long id) {
        studentMap.remove(id);
    }
}
  • Handler
package com.janeroad.controller;

import com.janeroad.entity.Student;
import com.janeroad.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.util.Collection;

@RestController
@RequestMapping("/student")
public class StudentHandler {
    @Autowired
    private StudentRepository studentRepository;
    @Value("${server.port}")
    private String port;
    @GetMapping("/findAll")
    public Collection findAll(){
        return studentRepository.findAll();
    }

    @GetMapping("/findById/{id}")
    public Student findById(@PathVariable("id") long id){
        return studentRepository.findById(id);
    }

    @PostMapping("/save")
    public void save(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }

    @PutMapping("/update")
    public void update(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }

    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") long id){
        studentRepository.deleteById(id);
    }

    @GetMapping("/index")
    public String index(){
        return "当前端口:"+this.port;
    }
}

打开浏览器,访问 http://localhost:8761,看到如下界面。

SpringCloud-Eureka与生产者消费者

运行eurekaclient启动类效果

SpringCloud-Eureka与生产者消费者
SpringCloud-Eureka与生产者消费者

RestTemplate 的使用

  • 什么是REST

REST是当前比较流行的一种互联网软件架构模型,通过统一的规范完成不同终端的数据访问和交互,REST是一个词组的缩写,全称为代表性状态转移,翻译成中文的意思是资源表现层状态转化。

特色

1、URL传参更加简洁,如下所示:

  • 非RESTful的URL:http://…../queryUserById?id=1
  • RESTful的URL:http://…./queryUserById/1

2、完成不同终端之间的资源共享,RESTful提供了一套规范,不同终端之间只需要遵守该规范,就可以实现数据交互。

Restful具体就是就是一种表现形式,HTTP协议的中部请求类型(GET,POST,PUT,DELETE)分别表示常规操作,即CRUD:

  • 获取获取资源
  • POST创造创造资源
  • 放置修改属性
  • DELETE用作删除资源

什么是RestTemplate

RestTemplate是Spring框架提供的基于REST的服务组件,通过对HTTP请求和响应进行了封装,提供了很多访问远程REST服务的方法,可简化代码开发。

  • 如何使用 RestTemplate?

1、创建 Maven 工程,pom.xml。

2、创建实体类

package com.janeroad.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private long id;
    private String name;
    private int age;
}

3、Handler

package com.janeroad.controller;
 
import com.janeroad.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
 
import java.util.Collection;
 
@RestController
@RequestMapping("/rest")
public class RestHandler {
    @Autowired
    private RestTemplate restTemplate;
    @GetMapping("/findAll")
    public Collection<Student> findAll(){
        return restTemplate.getForEntity("http://localhost:8010/student/findAll",Collection.class).getBody();
    }
 
    @GetMapping("/findAll2")
    public Collection<Student> findAll2(){
        return restTemplate.getForObject("http://localhost:8010/student/findAll",Collection.class);
    }
 
    @GetMapping("/findById/{id}")
    public Student findById(@PathVariable("id") long id){
        return restTemplate.getForEntity("http://localhost:8010/student/findById/{id}",Student.class,id).getBody();
    }
 
    @GetMapping("/findById2/{id}")
    public Student findById2(@PathVariable("id") long id){
        return restTemplate.getForObject("http://localhost:8010/student/findById/{id}",Student.class,id);
    }
 
    @PostMapping("/save")
    public void save(@RequestBody Student student){
        restTemplate.postForEntity("http://localhost:8010/student/save",student,null).getBody();
    }
 
    @PostMapping("/save2")
    public void save2(@RequestBody Student student){
        restTemplate.postForObject("http://localhost:8010/student/save",student,null);
    }
 
    @PutMapping("/update")
    public void update(@RequestBody Student student){
        restTemplate.put("http://localhost:8010/student/update",student);
    }
 
    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") long id){
        restTemplate.delete("http://localhost:8010/student/deleteById/{id}",id);
    }
}

4、启动类

package com.janeroad;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class RestTemplateApplication {
    public static void main(String[] args) {
        SpringApplication.run(RestTemplateApplication.class,args);
    }
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

RestTemplate不是一个微服务,就是一个单纯的Spring Boot应用,但是可以调用eurekaclient服务提供者的方法

RestTemplate启动效果

SpringCloud-Eureka与生产者消费者

服务消费者代码实现

实现一个用户的消费者,调用提供者的相关接口,实现思路是先通过Spring Boot构建一个微服务应用,再通过Eureka Client将其注册到Eureka Server。此时的提供者和消费者从代码的角度看并没有区别,都是Eureka客户端,我们人为地从业务角度对它们进行区分,提供者提供服务,消费者调用服务,具体的实现需要结合RestTemplate来完成,即在服务消费者Consumer中通过RestTemplate来调用服务提供者provider的相关接口。

SpringCloud-Eureka与生产者消费者
  • 创建 Maven 工程,pom.xml
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>2.0.2.RELEASE</version>
    </dependency>
</dependencies>
  • 创建配置文件 application.yml
server:
  port: 8020
spring:
  application:
    name: consumer
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
  • 创建启动类
package com.janeroad;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
    @Bean
    public RestTemplate restTemplate(){
        return  new RestTemplate();
    }
}
  • Handler
package com.janeroad.controller;

import com.janeroad.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.Collection;

@RestController
@RequestMapping("/consumer")
public class ConsumerHandler {
    @Autowired
    private RestTemplate restTemplate;
    @GetMapping("/findAll")
    public Collection findAll(){
        return restTemplate.getForEntity("http://localhost:8010/student/findAll",Collection.class).getBody();
    }

    @GetMapping("/findAll2")
    public Collection findAll2(){
        return restTemplate.getForObject("http://localhost:8010/student/findAll",Collection.class);
    }

    @GetMapping("/findById/{id}")
    public Student findById(@PathVariable("id") long id){
        return restTemplate.getForEntity("http://localhost:8010/student/findById/{id}",Student.class,id).getBody();
    }

    @GetMapping("/findById2/{id}")
    public Student findById2(@PathVariable("id") long id){
        return restTemplate.getForObject("http://localhost:8010/student/findById/{id}",Student.class,id);
    }

    @PostMapping("/save")
    public void save(@RequestBody Student student){
        restTemplate.postForEntity("http://localhost:8010/student/save",student,null).getBody();
    }

    @PostMapping("/save2")
    public void save2(@RequestBody Student student){
        restTemplate.postForObject("http://localhost:8010/student/save",student,null);
    }

    @PutMapping("/update")
    public void update(@RequestBody Student student){
        restTemplate.put("http://localhost:8010/student/update",student);
    }

    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") long id){
        restTemplate.delete("http://localhost:8010/student/deleteById/{id}",id);
    }
}

consumer实际上是一个服务消费者,间接地去访问数据

consumer启动效果

SpringCloud-Eureka与生产者消费者

其他增删改查的功能展示这里就省略了,可以用postman去测试


原文始发于微信公众号(JaneRoad):SpringCloud-Eureka与生产者消费者

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/23036.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!