收款定制开发SpringCloud-Eureka配置和使用

SpringCloud-配置

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

旧版本:spring-cloud-starter-eureka-serverspring-cloud-starter-eureka 例子如下,收款定制开发如果使用下面这种方法,收款定制开发有可能在配置其他方面报错,如

<!-- 服务端,收款定制开发收款定制开发面对注册中心 -->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-eureka-server</artifactId>            <version>1.4.7.RELEASE</version>        </dependency><!-- 客户端, 收款定制开发收款定制开发面对服务提供者和服务消费者-->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-eureka</artifactId>            <version>1.4.7.RELEASE</version>        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

新版本spring-cloud-starter-netflix-eureka-serverspring-cloud-starter-netflix-eureka-client 收款定制开发推荐使用新版本

<!-- 服务端,面对注册中心,收款定制开发注册中心收款定制开发导入此依赖 -->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>            <version>3.1.2</version>        </dependency><!-- 客户端, 面对服务提供者和服务消费者,provider和consumer导入此依赖-->		<dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>            <version>3.1.2</version>        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

收款定制开发服务端配置

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/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

启动类配置

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);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

服务提供者(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}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

启动类配置

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);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

服务消费者(consumer)配置

pom.xml

<dependencies>        <dependency>            <groupId>com.laoliu</groupId>            <artifactId>springcloud-api</artifactId>            <version>1.0-SNAPSHOT</version>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-devtools</artifactId>        </dependency>        	<dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>            <version>3.1.2</version>        </dependency>        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-config</artifactId>        </dependency>        <!--            springCloud2020 版本 把Bootstrap被默认禁用,            spring.config.import加入了对解密的支持。对于Config Client、Consul、Vault和Zookeeper的配置导入,            如果需要使用原来的配置引导功能,            那么需要将org.springframework.cloud:spring-cloud-starter-bootstrap依赖引入到工程中            这样才能正常使用springCloud        -->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-bootstrap</artifactId>        </dependency>    </dependencies>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

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

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

server:  port: 80eureka:  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/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

启动类配置

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);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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;@Configurationpublic class ConfigBean {    @Bean    @LoadBalanced //类属Ribbon,使用该注解说明让这个RestTemplate在请求时拥有客户端负载均衡的能力    public RestTemplate getRestTemplate(){        return new RestTemplate();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

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;@RestControllerpublic class DeptConsumerController {    /**     *  使用RestTemplate访问restful接口     * (url,requestMap,ResponseBean.class) 这三个参数分别代表     *  REST请求地址,请求参数,Http响应转换 被 转换成的对象类型     */    @Autowired    private RestTemplate restTemplate;//    private static final String REST_URL_PREFIX = "http://localhost:8001"; 没使用Euraka时的路径	/**	*	路径前缀发生改变,不在是地址,而是实例名称,就是服务提供者的实例名,作为Eureka的客户端,已经在配置文件application中配置好注册中心地址,	*	所以很好理解,配合Ribbon,负载均衡,选取合适的注册中心再通过实例名称和服务路径进行服务调用,此时实例名称大小写都可以	*/    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<Dept> 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);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

Ribbon注意事项

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

负载均衡算法替换

源码刨析

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

LoadBalancerClientConfiguration的源码有一项如下:

@ConditionalOnDiscoveryEnabledpublic class LoadBalancerClientConfiguration {    *******    @Bean    @ConditionalOnMissingBean //缺少该Bean时将会被启用,即可以自定义替换默认使用的负载均衡算法    public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {        String name = environment.getProperty("loadbalancer.client.name");        //默认轮询算法        return new RoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);    }        *******}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

正式替换

在新版的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();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

定义一个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;/***这个地方可以不加@Configuration,我的理解是@LoadBalancerClient拿到该类Class后通过反射会创建对象,*这其中的Bean将会被识别创建并替换原先的ReactorLoadBalancer,所以可以不用加,当然加上也可以运行,亲测可以。*/public class CustomLoadBalancerConfiguration {    @Bean //必须,不配置无法实现    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,                                                            LoadBalancerClientFactory loadBalancerClientFactory){        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);		//与源码类似,但是创建的是随机算法        return new RandomLoadBalancer(                loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class)                ,name);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

疑点及猜测

​ 通过源码可以看出,传进的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)@Documentedpublic @interface LoadBalancerClient {    @AliasFor("name")    String value() default "";    @AliasFor("value")    String name() default "";    Class<?>[] configuration() default {};}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

LoadBalancerClientConfigurationRegistrar源码:

public class LoadBalancerClientConfigurationRegistrar implements ImportBeanDefinitionRegistrar {    public LoadBalancerClientConfigurationRegistrar() {    }    private static String getClientName(Map<String, Object> 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<String, Object> 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<String, Object> client = metadata.getAnnotationAttributes(LoadBalancerClient.class.getName(), true);        String name = getClientName(client);        if (name != null) {        	//拿到configuration中的Class进行配置            registerClientConfiguration(registry, name, client.get("configuration"));        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

结语

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

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发