Spring Cloud 3.x 集成eureka快速入门Demo

1.什么是eureka?

Eureka 由 Netflix 开发,是一种基于REST(Representational State Transfer)的服务,用于定位服务(服务注册与发现),以实现中间层服务的负载均衡和故障转移,此服务被称为 Eureka Server。同时,它还附带了基于 Java 的客户端组件:Eureka Client,它使得客户端与 Eureka Server 的交互变得更加的容易。

  • Register(服务注册):把自己的IP和端口注册给Eureka。
  • Renew(服务续约):发送心跳包,每30秒发送一次。告诉Eureka自己还活着。
  • Cancel(服务下线):当provider关闭时会向Eureka发送消息,把自己从服务列表中删除。防止consumer调用到不存在的服务。
  • Get Registry(获取服务注册列表):获取其他服务列表。
  • Replicate(集群中数据同步):eureka集群中的数据复制与同步。
  • Make Remote Call(远程调用):完成服务的远程调用。

Eureka Server

Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。

Eureka Client

Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。

2.环境搭建

eureka主要作为注册中心使用,搭建2节点集群

pom.xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>eureka</artifactId>
        <groupId>com.et</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka-server</artifactId>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

</project>

noode1

复制代码
server:
  port: 8761

eureka:
  instance:
    hostname: node1 # eureka name
    prefer-ip-address: false
  client:
    fetch-registry: false
    register-with-eureka: true
    # eureka url
    service-url:
      defaultZone: http://node2:8762/eureka
spring:
  application:
    name: "eureka-server-ha"

management:
  endpoints:
    web:
      exposure:
        include: "*"

node2

复制代码
server:
  port: 8762

eureka:
  instance:
    hostname: node2 # eureka name
    prefer-ip-address: false
  client:
    fetch-registry: false
    register-with-eureka: true
    # eureka url
    service-url:
      defaultZone: http://node1:8761/eureka
spring:
  application:
    name: "eureka-server-ha"

management:
  endpoints:
    web:
      exposure:
        include: "*"

启动类

复制代码
package com.et.eureka;

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);
  }
}

启动node1和node2,访问http://node2:8762/

3.代码工程

实验目标

实现消费者调用生产者服务

生产者

提供服务接口 pom.xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>eureka</artifactId>
        <groupId>com.et</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka-provider</artifactId>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>


</project>

controller

复制代码
package com.er.eureka.provider.controller;

import com.er.eureka.provider.model.Student;
import com.er.eureka.provider.service.StudentService;
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 StudentService studentService;
    @Value("${server.port}")
    private String port;
    @GetMapping("/findAll")
    public Collection findAll(){
        return studentService.findAll();
    }

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

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

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

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

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

service

复制代码
package com.er.eureka.provider.service;

import com.er.eureka.provider.model.Student;

import java.util.Collection;

public interface StudentService {
    public Collection findAll();
    public Student findById(long id);
    public void saveOrUpdate(Student student);
    public void deleteById(long id);
}

package com.er.eureka.provider.service;

import com.er.eureka.provider.model.Student;
import org.springframework.stereotype.Repository;

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

@Repository
public class StudentServiceImpl implements StudentService {
    private static Map studentMap;
    static {
        studentMap = new HashMap<>();
        studentMap.put(1L,new Student(1L,"zhangsan",22));
        studentMap.put(2L,new Student(2L,"lisi",23));
        studentMap.put(3L,new Student(3L,"wangwu",24));
    }

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

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

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

    @Override
    public void deleteById(long id) {
        studentMap.remove(id);
    }
}

application.yaml

复制代码
server:
  port: 8011
spring:
  application:
    name: provider
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

management:
  endpoints:
    web:
      exposure:
        include: "*"

启动类

复制代码
package com.er.eureka.provider;

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


@SpringBootApplication
public class DemoApplication {

   public static void main(String[] args) {
      SpringApplication.run(DemoApplication.class, args);
   }
}

消费者

调用服务者提供的接口 pom.xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>eureka</artifactId>
        <groupId>com.et</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka-consumer</artifactId>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

    </dependencies>
</project>

controller

复制代码
package com.et.eureka.consumer.controller;

import com.et.eureka.consumer.model.Student;
import com.et.eureka.consumer.service.MyFeignClient;
import com.netflix.appinfo.InstanceInfo;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.Collection;
import java.util.List;

@RestController
@RequestMapping("/consumer")
@Slf4j
public class ConsumerHandler {
    @Autowired
    RestTemplate restTemplate;
    @Resource
    private DiscoveryClient discoveryClient;
    @Autowired
    private MyFeignClient myFeignClient;
    @GetMapping("/findAll")
    public String findAll(){
        return myFeignClient.findAll();
    }

    @GetMapping("/findAll2")
    public Collection findAll2(){
        return restTemplate.getForObject("http://PROVIDER/student/findAll",Collection.class);
    }
    @GetMapping("/findAll3")
    public String findAll3(){
        RestTemplate restTemplate = new RestTemplate();
        List<ServiceInstance> instances = discoveryClient.getInstances("PROVIDER");
        if (instances == null || instances.size() == 0) {
            log.info("instances is empty..");
            return "";
        }

        String uri = instances.get(0).getUri().toString();
        String serviceUrl = String.format("%s/student/findAll", uri);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity entity = new HttpEntity(headers);
        log.info("uri is :{},formatted url is:{}", uri, serviceUrl);
        ResponseEntity<String> resultExchange = restTemplate.exchange(serviceUrl, HttpMethod.GET, entity, String.class, "");
        if (resultExchange == null) {
            log.info("invoke result is null");
            return "";
        }
        String body = resultExchange.getBody();
        log.info("body is :{}", body);
        return body;


    }

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

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

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

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

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

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

service

复制代码
package com.et.eureka.consumer.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient(name = "provider")
public interface MyFeignClient {

    @GetMapping("/student/findAll")
    String findAll();
}

启动类

复制代码
package com.et.eureka.consumer;

import com.netflix.discovery.DiscoveryClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

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


}

application.yaml

复制代码
server:
  port: 8020
spring:
  application:
    name: consumer
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
management:
  endpoints:
    web:
      exposure:
        include: "*"

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

4.测试

  • 启动node1
  • 启动node2
  • 启动服务端
  • 启动消费端

可以看到服务者和消费者都注册到eureka注册中心上

访问http://127.0.0.1:8020/consumer/findAll,会调用服务服务端接口并返回数据。

5.引用

相关推荐
小羊在睡觉28 分钟前
golang定时器
开发语言·后端·golang
pengzhuofan34 分钟前
第10章 Maven
java·maven
用户214118326360238 分钟前
手把手教你在魔搭跑通 DeepSeek-OCR!光学压缩 + MoE 解码,97% 精度还省 10-20 倍 token
后端
追逐时光者43 分钟前
一个基于 .NET 开源、功能强大的分布式微服务开发框架
后端·.net
百锦再1 小时前
Vue Scoped样式混淆问题详解与解决方案
java·前端·javascript·数据库·vue.js·学习·.net
刘一说1 小时前
Spring Boot 启动慢?启动过程深度解析与优化策略
java·spring boot·后端
壹佰大多1 小时前
【spring如何扫描一个路径下被注解修饰的类】
java·后端·spring
wudl55661 小时前
Docker 常用命令
docker·容器·eureka
百锦再1 小时前
对前后端分离与前后端不分离(通常指服务端渲染)的架构进行全方位的对比分析
java·开发语言·python·架构·eclipse·php·maven
间彧1 小时前
Java双亲委派模型的具体实现原理是什么?
后端