栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringCloud-Eureka配置和使用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringCloud-Eureka配置和使用

SpringCloud-Eureka配置

注意:Eureka新旧版本情况,旧版本已经被弃用,需要(建议)使用新的版本

旧版本:spring-cloud-starter-eureka-server,spring-cloud-starter-eureka 例子如下,如果使用下面这种方法,有可能在配置其他方面报错,如Ribbon


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

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

新版本:spring-cloud-starter-netflix-eureka-server,spring-cloud-starter-netflix-eureka-client 推荐使用新版本


        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-server
            3.1.2
        

		
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
            3.1.2
        
服务端配置

application.yaml配置如下

server:
  port: 7001

#Eureka 服务端配置,(服务端,创建服务,让其他客户端(provider,consumer)可以注册服务或拿取注册服务)
eureka:
  instance:
    hostname: eureka7001.com #eureka服务端名称
  client:
    register-with-eureka: false # 是否将自己注册到Eureka服务器中,本身是服务器,无需注册
    fetch-registry: false # false表示自己就是注册中心,只需要维护服务实例,无需检索服务
    service-url:
      # 设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个defaultZone地址
#      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ # 单机设置
	#开启集群设置如下,连接其他的注册主机
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

启动类配置

package com.laoliu.springcloud;

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

@SpringBootApplication
@EnableEurekaServer  //开启Eureka服务端服务
public class EurekaServer7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer7001.class);
    }
}
服务提供者(provider)配置

application.yaml配置

server:
  port: 8001

# mybatis 设置
mybatis:
  config-location: classpath:mybatis/mybatis-config.xml
  type-aliases-package: com.laoliu.springcloud.pojo
  mapper-locations:
    - classpath:mybatis/mapper*.xml

# spring相关配置
spring:
  application:
    name: springcloud-provider-dept  #实例名称,服务消费者使用的rest请求,需要这个实例名称
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud
    username: root
    password: root
    dbcp2:
      min-idle: 5
      initial-size: 5
      max-total: 5
      max-wait-millis: 200
#eureka 客户端配置
eureka:
  client:
    service-url:
      # 将8001微服务发布到1台eureka集群配置中,发现在集群中的其余注册中心也可以看到,但是平时我们保险起见,都发布!
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: springcloud-provider-dept8001
    prefer-ip-address: true

#监控短点配置,springboot2.5以后,默认只开启health,需要手动打开其他
management:
  endpoints:
    web:
      exposure:
        include: "*" # 全部打开

#info配置
info:
  app.name: laoliu-springcloud
  company.name: www.laoliu.com
  build.artifactId: ${project.artifactId}
  build.version: ${project.version}

启动类配置

package com.laoliu.springcloud;

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
@EnableEurekaClient //开启客户端服务
@EnableDiscoveryClient //扫描所有的服务提供到注册中心中
public class DeptProvider8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider8001.class);
    }
}
服务消费者(consumer)配置

pom.xml


        
            com.laoliu
            springcloud-api
            1.0-SNAPSHOT
        

        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-devtools
        
    
    	
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
            3.1.2
        
        
            org.springframework.cloud
            spring-cloud-starter-config
        
        
        
            org.springframework.cloud
            spring-cloud-starter-bootstrap
        
    

注意:SpringCloud 从2020 版本 把Bootstrap被默认禁用,spring.config.import加入了对解密的支持。对于Config Client、Consul、Vault和Zookeeper的配置导入,如果需要使用原来的配置引导功能,那么需要将org.springframework.cloud:spring-cloud-starter-bootstrap依赖引入到工程中这样才能正常使用springCloud

application.yaml配置(此配置集成Ribbon)

server:
  port: 80

eureka:
  client:
    register-with-eureka: false # false 不是服务提供者,不需要注册到Eureka中
    fetch-registry: true # true 消费者需要检索注册中心服务才能调用实例,否则找不到实例,调用失败,报错!!!!!
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

启动类配置

package com.laoliu.springcloud;

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

@SpringBootApplication
@EnableEurekaClient //开启客户端
public class DeptConsumerRibbon80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumerRibbon80.class,args);
    }
}

ConfigBean配置

package com.laoliu.springcloud.config;

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 ConfigBean {

    @Bean
    @LoadBalanced //类属Ribbon,使用该注解说明让这个RestTemplate在请求时拥有客户端负载均衡的能力
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

controller(例子说明)

package com.laoliu.springcloud.controller;

import com.laoliu.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
public class DeptConsumerController {

    
    @Autowired
    private RestTemplate restTemplate;

//    private static final String REST_URL_PREFIX = "http://localhost:8001"; 没使用Euraka时的路径

	
    private static final String REST_URL_PREFIX = "http://springcloud-provider-dept";
    

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

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

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

    @GetMapping("/consumer/dept/discovery")
    public Object discovery(){
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/discovery",Object.class);
    }
}
Ribbon注意事项

消费者模块所需要的Ribbon在新版的Eureka中已经被弃用(或者说是内置),不可以再导入依赖,导入spring-cloud-starter-netflix-ribbon将会找不到实例,报错!!!

负载均衡算法替换 源码刨析

读取源码可知,新版的Eureka的LoadBalanced实现了两种负载均衡的算法:轮询算法(默认)和随机算法

LoadBalancerClientConfiguration的源码有一项如下:

@ConditionalOnDiscoveryEnabled
public class LoadBalancerClientConfiguration {
    ****略***
    @Bean
    @ConditionalOnMissingBean //缺少该Bean时将会被启用,即可以自定义替换默认使用的负载均衡算法
    public ReactorLoadBalancer reactorServiceInstanceLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty("loadbalancer.client.name");
        //默认轮询算法
        return new RoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
    
    ****略***
}
正式替换

在新版的Eureka中使用@LoadBalanced进行客户端请求负载均衡,默认使用的算法是轮询(即轮流调用实例中的服务),可以将算法修改为随机,示例如下:

ConfigBean

package com.laoliu.springcloud.config;

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
@LoadBalancerClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = CustomLoadBalancerConfiguration.class)//name为服务实例名称,configuration是自定义好的算法类
public class ConfigBean {

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

定义一个CustomLoadBalancerConfiguration类来替换算法

package com.laoliu.springcloud.config;

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;


public class CustomLoadBalancerConfiguration {

    @Bean //必须,不配置无法实现
    ReactorLoadBalancer randomLoadBalancer(Environment environment,
                                                            LoadBalancerClientFactory loadBalancerClientFactory){
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
		//与源码类似,但是创建的是随机算法
        return new RandomLoadBalancer(
                loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class)
                ,name);

    }
}
疑点及猜测

​ 通过源码可以看出,传进的CustomLoadBalancerConfiguration类会通过反射机制创建对应的CustomLoadBalancerConfiguration对象或者类中被标识为Bean的ReactorLoadBalancer,然后替换为原先的算法配置,原本我以为应该是反射后创建的对象给spring托管,但是当我用@Autowired输出验证该对象时为空,证明该对象应该不是由spring托管,继续验证@Bean,当我未加入@Bean时,算法没被替换,当我加入@Bean后,算法替换成功,但是用@Autowired输出验证ReactorLoadBalancer为空,最后我得出结论:

  1. CustomLoadBalancerConfiguration类中ReactorLoadBalancer必须有@Bean标识,反射的对象有两种可能:
    • 一种是反射出CustomLoadBalancerConfiguration对象,然后找到标识为@Bean的ReactorLoadBalancer创建并替换原来算法。
    • 另一种是反射机制先识别@Bean标志的ReactorLoadBalancer,然后直接创建并替换原算法(我认为可能性很大)
  2. 反射出的ReactorLoadBalancer不由Spring托管,通过@Autowired无法拿出(疑惑又肯定)
  3. 基本上可以确定是由@Bean标识然后反射对象进行替换
部分源码

LoadBalancerClient源码:

@Configuration(
    proxyBeanMethods = false
)
@Import({LoadBalancerClientConfigurationRegistrar.class})
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoadBalancerClient {
    @AliasFor("name")
    String value() default "";

    @AliasFor("value")
    String name() default "";

    Class[] configuration() default {};
}

LoadBalancerClientConfigurationRegistrar源码:

public class LoadBalancerClientConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
    public LoadBalancerClientConfigurationRegistrar() {
    }

    private static String getClientName(Map client) {
        if (client == null) {
            return null;
        } else {
            String value = (String)client.get("value");
            if (!StringUtils.hasText(value)) {
                value = (String)client.get("name");
            }

            if (StringUtils.hasText(value)) {
                return value;
            } else {
                throw new IllegalStateException("Either 'name' or 'value' must be provided in @LoadBalancerClient");
            }
        }
    }

    private static void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(LoadBalancerClientSpecification.class);
        builder.addConstructorArgValue(name);
        builder.addConstructorArgValue(configuration);
        //这个获取Bean定义,正是我考虑的由@Bean识别进行反射
        registry.registerBeanDefinition(name + ".LoadBalancerClientSpecification", builder.getBeanDefinition()); 
        
    }

    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        Map attrs = metadata.getAnnotationAttributes(LoadBalancerClients.class.getName(), true);
        if (attrs != null && attrs.containsKey("value")) {
            AnnotationAttributes[] clients = (AnnotationAttributes[])((AnnotationAttributes[])attrs.get("value"));
            AnnotationAttributes[] var5 = clients;
            int var6 = clients.length;

            for(int var7 = 0; var7 < var6; ++var7) {
                AnnotationAttributes client = var5[var7];
                registerClientConfiguration(registry, getClientName(client), client.get("configuration"));
            }
        }

        if (attrs != null && attrs.containsKey("defaultConfiguration")) {
            String name;
            if (metadata.hasEnclosingClass()) {
                name = "default." + metadata.getEnclosingClassName();
            } else {
                name = "default." + metadata.getClassName();
            }

            registerClientConfiguration(registry, name, attrs.get("defaultConfiguration"));
        }

        Map client = metadata.getAnnotationAttributes(LoadBalancerClient.class.getName(), true);
        String name = getClientName(client);
        if (name != null) {
        	//拿到configuration中的Class进行配置
            registerClientConfiguration(registry, name, client.get("configuration"));
        }

    }
}
结语

源码部分没有过度深究,如果有大神深入了解过源码,请求在评论区或者私聊我为我指点迷津,上文有错的地方也请各位不吝指出,我将进行改正和学习,最后感谢各位的观看!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/880681.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号