SpringCloud之Ribbon+Eureka集成笔记

博客地址:单身博客 | LamBlog (lamzy.top)

目录:

一、介绍

二、父Maven

三、Api搭建

四、提供者

五、注册中心

六、消费者


一、介绍

搭建环境:Jdk1.8 、Mysql 、Windows/Linux CentOs 、Idea


二、父Maven

xml version="1.0" encoding="UTF-8"?>
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">
    4.0.0

    com.github
    lamzier
    1.0-SNAPSHOT
    
        SpringCloud-Api
        SpringCloud-consumer-dept-80
        SpringCloud-eureka-7001
        SpringCloud-eureka-7002
        SpringCloud-eureka-7003
        SpringCloud-provider-dept-8001
        SpringCloud-provider-dept-8002
        SpringCloud-provider-dept-8003
    

    
    
        UTF-8
        1.8
        1.8
        4.13.2
        1.18.24
        1.2.17
    

    
    pom

    
    
        
            
            
            
                org.springframework.cloud
                spring-cloud-dependencies
                2021.0.3
                pom
                import
            
            
            
            
                org.springframework.boot
                spring-boot-dependencies
                2.7.2
                pom
                import
            
            
            
            
                mysql
                mysql-connector-java
                8.0.30
            
            
            
                com.alibaba
                druid
                1.2.11
            
            
            
            
                org.mybatis.spring.boot
                mybatis-spring-boot-starter
                2.2.2
            
            
            
            
                junit
                junit
                ${junit.version}
            
            
            
                org.projectlombok
                lombok
                ${lombok.version}
            
            
            
                log4j
                log4j
                ${log4j.version}
            
            
            
                ch.qos.logback
                logback-core
                1.2.11
            
        
    


三、Api搭建

包结构图

package com.github.lamzier.pojo;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;

@Data
@NoArgsConstructor
@Accessors(chain = true) //开启 链式写法
public class Dept implements Serializable { //实体类 实现序列化 , 类表关系映射

    private Long deptno;//主键
    private String dname;

    //这个数据是存在哪个数据库的字段~ 微服务:一个服务对应一个数据库,同一个信息可能存在不同的数据库
    private String DbSource;

    public Dept(String dname){
        this.dname = dname;
    }

    /*
    链式写法:
        Db01 db01 = new Db01();
        db01.setDeptno(11).setDname('阿西吧').setDb_source('001');

     */

}

Dept.java

依赖:Lombok (省略了)


四、提供者

SpringCloud之Ribbon+Eureka集成笔记_第1张图片

文件结构图

package com.github.lamzier.controller;

import com.github.lamzier.pojo.Dept;
import com.github.lamzier.service.DeptService;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;

//提供Restful 服务
@RestController
public class DdptController {

    @Resource
    private DeptService deptService;

    //获取一些配置信息,得到具体的微服务
    @Resource
    private DiscoveryClient discoveryClient;

    @PostMapping("/dept/add")
    public boolean addDept(Dept dept){
        return deptService.addDept(dept);
    }

    @GetMapping("/dept/get/{id}")
    public Dept get(@PathVariable long id){
        return deptService.queryDeptById(id);

    }

    @GetMapping("/dept/list")
    public List list(){
        return deptService.queryAllDept();
    }

    //注册进来的微服务,获取一些消息
    @GetMapping("/dept/discovery")
    public Object discovery(){
        //获取服务列表的清单
        List services = discoveryClient.getServices();
        System.err.println("discovery=>services:" + services);

        //得到一个具体的微服务信息 , 通过具体的微服务id , applicationName
        List instances = discoveryClient.getInstances("SPRINGCLOUD-PROVIDER-DEPT-8001");
        for (ServiceInstance instance : instances) {
            System.err.println(
                    instance.getHost() + "\t" +
                    instance.getPort() + "\t" +
                    instance.getUri() + "\t" +
                    instance.getServiceId()
            );
        }
        return this.discoveryClient;
    }


}

控制层:DdptController.java

数据层:省略

服务层:省略

package com.github.lamzier;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

//启动类
@SpringBootApplication
//@MapperScan("com.github.lamzier.dao")
@EnableEurekaClient // 开启EurekaClient 在服务启动后自动注册到Eureka@EnableDiscoveryClient //开启服务发现
public class DeptProvider_8001 {

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

启动类 DeptProvider_8001

Mapper配置:省略

server:
  port: 8001

#mybatis 配置
mybatis:
  type-aliases-package: com.github.lamzier.pojo
#  config-location: classpath:mybatis/mybatis-config.xml #不能喝configuration同时使用
  mapper-locations: classpath:mybatis/mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true #驼峰转换
    cache-enabled: true #开启二级缓存

#Spring 的配置
spring: 
  application:
    name: springcloud-provider-dept # 3个服务名称一一致
  datasource: #注意!这里每个服务配置一个自己的数据库
    type: com.alibaba.druid.pool.DruidDataSource #数据源
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test1?userUnicode=true&characterEncoding=utf-8
    username: test1 
    password: test1

#Eureka 的配置
eureka:
  client:
    service-url:
      #注册中心地址
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: springCloud-provider-dept8001 #修改eureka上的默认描述信息

#info 配置
info:
  app:
    name: lamzy-springcloud
  company:
    name: gdei.lamzy.top
#管理开启
management:
  info:
    env:
      enabled: true
  endpoints:
    web:
      exposure:
        include: "*"

配置:application.yml

xml version="1.0" encoding="UTF-8"?>
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">
    
        lamzier
        com.github
        1.0-SNAPSHOT
    
    4.0.0

    SpringCloud-provider-dept-8001

    
        1.8
        1.8
    

    
        
        
            com.github
            SpringCloud-Api
            1.0-SNAPSHOT
        
        
        
            junit
            junit
        
        
        
            mysql
            mysql-connector-java
        
        
        
            com.alibaba
            druid
        
        
        
            ch.qos.logback
            logback-core
        
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
        
        
        
            org.springframework.boot
            spring-boot-test
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.springframework.boot
            spring-boot-starter-jetty
        
        
        
            org.springframework.boot
            spring-boot-devtools
        
        
        
        
            org.springframework.cloud
            spring-cloud-starter-eureka
            1.4.7.RELEASE
        
        
        
            org.springframework.boot
            spring-boot-starter-actuator
        



    

pom依赖


五、注册中心

SpringCloud之Ribbon+Eureka集成笔记_第2张图片

文件结构图

package com.github.lamzier;

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

//启动后,访问http://localhost:7001/
@SpringBootApplication
@EnableEurekaServer // 开启EurekaServer 服务端的启动类,可以接收别人注册进来
public class EurekaServer_7001 {

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

}

启动类:EurekaServer_7001.java

server:
  port: 7001

#Eureka配置
eureka:
  instance:
    hostname: eureka7001.com # Eureka 服务端名字
  client:
    register-with-eureka: false # 表示是否向Eureka注册中心注册自己
    fetch-registry: false # 如果为 false , 则表示自己为注册中心
    # 监控页面
    service-url:
      #单机:       defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      #集群(关联):
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

配置:application.yml

xml version="1.0" encoding="UTF-8"?>
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">
    
        lamzier
        com.github
        1.0-SNAPSHOT
    
    4.0.0

    SpringCloud-eirela-7001

    
        1.8
        1.8
    

    
        
        
        
            org.springframework.cloud
            spring-cloud-starter-eureka-server
            1.4.7.RELEASE
        
        
        
            org.springframework.boot
            spring-boot-devtools
        



    

pom依赖


六、消费者

SpringCloud之Ribbon+Eureka集成笔记_第3张图片

文件结构图

package com.github.lamzier;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
//import org.springframework.cloud.netflix.ribbon.RibbonClient;

//Ribbon  Eureka 整合以后, 客户端可以直接调用,不用关心Ip地址和端口号
@SpringBootApplication
@EnableEurekaClient //启动Eureka客户端
//@RibbonClient(name = "springcloud-provider-dept")
public class DeptConsumer_80 {

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

}

启动类:DeptConsumer_80.java

package com.github.lamzier.controller;

import com.github.lamzier.pojo.Dept;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.List;

@RestController
public class DeptConsumerController {

    // 理解:消费者,不应该有service    // RestTemplate ...... 供我们直接调用就可以了!,注册到Spring    // (url , 实体:Map , Class responseType)
    @Resource
    private RestTemplate restTemplate; // 提供多种边界访问远程http服务的方法 , 简单的restful服务模板~

    //Ribbon。我们这里的地址,应该是一个变量,通过服务名来访问
//    private static final String REST_URL_PREFIX = "http://localhost:8001";
    private static final String REST_URL_PREFIX = "http://springcloud-provider-dept";

    @RequestMapping("/consumer/dept/get/{id}")
    public Dept get(@PathVariable("id") long id){
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
    }

    @RequestMapping("/consumer/dept/add")
    public Boolean add(Dept db01){
        return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add" , db01 , Boolean.class);
    }

    @RequestMapping("/consumer/dept/list")
    public List list(){
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list" , List.class);
    }

}

控制层:DeptConsumerController.java

package com.github.lamzier.config;

import com.github.lamzier.myrule.LamzyRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
//加载自动加载的Ribbon@LoadBalancerClient(name = "springcloud-provider-dept",configuration = LamzyRule.class)
public class ConfigBean { // @Configuration --- spring applicationContext.xml

    //配置负载均衡,实现RestTemplate
    // IRULE
    // RoundRobinRule : 轮询 默认
    // RandomRule : 随机
    // AvailabilityFilteringRule : 会先过滤掉跳闸的服务,对剩下的进行轮询
    // RetryRule : 会先按照轮询获取服务,如果服务获取失败,则会在指定的时间内进行重试
    @Bean
    @LoadBalanced //Ribbon
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }


}

Ribbon配置类:ConfigBean.java

注意:在新版本中负载均衡的算法或者使用自定义算法不在这里配置,具体配置方法后面会讲。

package com.github.lamzier.myrule;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;

//这里 不需要 @configuration注解  不需要 不需要
public class LamzyRule {

    @Bean
    ReactorLoadBalancer randomLoadBalancer(Environment environment,
                                                            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);

        //随机算法
//        return new RandomLoadBalancer(loadBalancerClientFactory
//                .getLazyProvider(name, ServiceInstanceListSupplier.class),
//                name);

        //自定义算法
        return new PeachLoadBalancer(loadBalancerClientFactory
                .getLazyProvider(name, ServiceInstanceListSupplier.class),
                name);


    }
}

负载均衡算法配置:LamzyRule.java

package com.github.lamzier.myrule;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.core.*;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

//这个方法基本是copyRoundRobinLoadBalancer自己改一改出来的
public class PeachLoadBalancer implements ReactorServiceInstanceLoadBalancer {
    private static final Log log = LogFactory.getLog(RoundRobinLoadBalancer.class);

    final AtomicInteger position;//请求的次数

    final String serviceId; //服务名称 用于提示报错信息的

    private int flag = 0; //自己定义的计数器

    //两个参数的构造方法 需要服务名称和实例提供者 这个在方法中传递进来
    public PeachLoadBalancer(ObjectProvider serviceInstanceListSupplierProvider,
                             String serviceId) {
        //如果不传人请求次数就自己初始化 反正每次都+1
        this(new Random().nextInt(1000), serviceId,serviceInstanceListSupplierProvider);
    }

    public PeachLoadBalancer(int seedPosition, String serviceId, ObjectProvider serviceInstanceListSupplierProvider) {
        this.position = new AtomicInteger(seedPosition);
        this.serviceId = serviceId;
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
    }

    ObjectProvider serviceInstanceListSupplierProvider;
    @Override
    public Mono> choose(Request request) {
        //从服务提供者中获取到当前request请求中的serviceInstances并且遍历
        ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
                .getIfAvailable(NoopServiceInstanceListSupplier::new);
        return supplier.get(request).next()
                .map(serviceInstances -> processInstanceResponse(supplier, serviceInstances));
    }

    private Response processInstanceResponse(ServiceInstanceListSupplier supplier,
                                                              List serviceInstances) {
        Response serviceInstanceResponse = getInstanceResponse(serviceInstances);
        if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
            ((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer());
        }
        return serviceInstanceResponse;
    }

    private Response getInstanceResponse(List instances) {
        if (instances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.warn("No servers available for service: " + serviceId);
            }
            return new EmptyResponse();
        }
        //pos是当前请求的次数 这样可以自定义负载均衡的切换  这个每次+1的操作是复制的 最好是不删
        int pos = Math.abs(this.position.incrementAndGet());

        if (pos%4==0){
            //4的倍数就切换
            flag += 1;
        }
        if (flag >= instances.size()){
            flag = 0;
        }
        //主要的就是这句代码设置负载均衡切换
        ServiceInstance instance = instances.get(flag);
        return new DefaultResponse(instance);
    }
}

负载均衡自定义算法:PeachLoadBalancer.java

server:
  port: 80

# Eureka配置
eureka:
  client:
    register-with-eureka: false #不向Eureka注册自己
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

配置:application.yml

xml version="1.0" encoding="UTF-8"?>
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">
    
        lamzier
        com.github
        1.0-SNAPSHOT
    
    4.0.0

    SpringCloud-consumer-

    
        1.8
        1.8
    

    
        
        
            com.github
            SpringCloud-Api
            1.0-SNAPSHOT
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.springframework.boot
            spring-boot-devtools
        
        
        
            org.springframework.boot
            spring-boot-starter-jetty
        
        
        






        
        
        
            org.springframework.cloud
            spring-cloud-starter-eureka
            1.4.7.RELEASE
        
    

pom依赖

注意:在新版本中spring-cloud-starter-eureka-client依赖默认包含ribbon,因此只需要导入spring-cloud-starter-eureka或者spring-cloud-starter-eureka-client即可!不需要再导入spring-cloud-starter-netfix-ribbon!否则会报500异常,找不到服务。


最后总结

在新版本中的负载均衡变化较大,而且导包也不同

最后博客更新时间:2022年8月10日 1:42

你可能感兴趣的:(eureka,spring,cloud,ribbon)