zoukankan      html  css  js  c++  java
  • 玩转Spring Cloud之服务注册发现(eureka)及负载均衡消费(ribbon、feign)

      如果说用Spring Boot+Spring MVC是开发单体应用(或单体服务)的利器,那么Spring Boot+Spring MVC+Spring Cloud将是开发分布式应用(快速构建微服务)的又一法宝,相信大家如果看到我近期总结的《JAVA WEB快速入门》系列文章,对Spring Boot+Spring MVC应该是比较熟悉了吧,从本文开始,一起来熟悉Spring Cloud、玩转Spring Cloud,至于什么是Spring Cloud?我这里就不再介绍了,网上资源太多了,比如:大话Spring CloudSpringCloud是什么?,当然介绍Spring Cloud系列文章也比较多(比如:https://blog.csdn.net/forezp/article/details/70148833),大家也可以参考,我这里只是结合当前最新的Spring Boot、Spring MVC、Spring Cloud来重新演练一遍,把重要的知识点、遇到的一些坑分享出来,一来是为自己做记录(所谓“好记性不如烂笔头”),二来可以避免大家学习时走弯路,又因为介绍Spring Cloud文章实在太多了,故玩转Spring Cloud系列文章更多的是以把实现的DEMO代码一步步贴出来,一些组件名词我就不再详细解释了,然后对于涉及的重要知识点及踩坑点进行说明,以便大家可以:知其然还能知其所以然。(注:所有示例代码均采用IDEA IDE编写)

    一、实现eureka server(注册中心)

      1.1.通过IDEA来创建一个空的spring boot项目(类型是:maven-archtype-quickstart,这样最精简,当然如果你使用webapp项目也是可以,只是认为没有必要)。

        创建步骤有2种,第一种是使用maven创建: maven->maven-archtype-quickstart,然后手动添加相关的spring boot依赖;第二种是使用spring initializer->填写项目参数->选择相关依赖(可直接选择spring cloud相关依赖,如:eureka,这样就一步到位,这里全部先不选),最终的初始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">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>cn.zuowenjun.cloud</groupId>
      <artifactId>eurekaserver</artifactId>
      <version>1.0-SNAPSHOT</version>
    
      <name>eurekaserver</name>
      <!-- FIXME change it to the project's website -->
      <url>http://www.zuowenjun.cn</url>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
      </properties>
    
      <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
      </parent>
    
    
    
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
    
    
      </dependencies>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
        </plugins>
      </build>
    
    </project>

    如上所示(如果不是请改成这样,如果只是多点依赖没关系,当然我认为此时只需要这么多的依赖即可,多了也无用),我们只是有spring boot的POM依赖,并没有spring cloud的相关依赖。

      1.2添加spring cloud相关依赖,如下所示:(添加了dependencyManagement节点,并配置spring-cloud-dependencies pom import依赖,目的是:便于依赖继承,与parent节点功能类似,添加具体依赖时,若包含在parent中或pom import依赖中则无需版本号,能够保证组件的一致性,详见:https://blog.csdn.net/mn960mn/article/details/50894022,相反如果没有配置spring-cloud-dependencies pom import依赖,则添加具体依赖时需要指定version版本号,而且需要注意各依赖组件间的兼容性问题,如下面我把version注释掉)

      <dependencyManagement>
      <dependencies>
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-dependencies</artifactId>
          <version>Greenwich.RELEASE</version>
          <type>pom</type>
          <scope>import</scope>
        </dependency>
      </dependencies>
    </dependencyManagement>
    
      <dependencies>
        ... ...其它原有依赖
        
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter</artifactId>
          <!--<version>2.1.0.RELEASE</version>-->
        </dependency>
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
          <!--<version>2.1.0.RELEASE</version>-->
        </dependency>
    
      </dependencies>

      1.3.在resouces目录下(若没有请创建,注意设为souces root目录,方法:右键文件夹->Mark directory as->souces root)创建application.yml(或application.properties,本文示例全部使用yml),添加如下配置:

    server:
      port: 8800
    
    spring:
      applcation:
        name: demo-eurekaserver
    
    # config detail:https://www.jianshu.com/p/98f4e5f6bca7  or https://blog.csdn.net/wo18237095579/article/details/83276352
    eureka:
      instance:
        hostname: eurekaserver1 #实例主机名,集群时需要且唯一
      server:
        enable-self-preservation: true #自我保护,正式环境不要这么做
        eviction-interval-timer-in-ms: 5000 #定期清理失效节点,默认60s
        peer-eureka-nodes-update-interval-ms: 6000 #同步更新节点频率,默认10min
        renewal-percent-threshold: 0.49 #默认0.85
        response-cache-auto-expiration-in-seconds: 30
    
      client:
        registerWithEureka: false
        fetchRegistry: false
        serviceUrl:
          defaultZone: http://localhost:${server.port}/eureka/

    1.4.在spring boot 启动类中添加@EnableEurekaServer即可,如下代码:

    package cn.zuowenjun.cloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    @EnableEurekaServer
    @SpringBootApplication
    public class App 
    {
        public static void main( String[] args )
        {
            SpringApplication.run(App.class, args);
        }
    }
    View Code

    整个项目结构如下图示,启动后浏览地址:http://localhost:8800/,会出现spring eureka的主页,就表明eureka server成功了。

    二、实现service provider(含eureka  client)--服务提供者

    【即:具体微服务项目,注册服务信息,暴露API】,当然也有可能同时是service consumer【服务消费者】,需要远程调用其它服务

      2.1.参照1.1方式创建一个空的spring boot项目,然后添加spring cloud 相关依赖(这里主要是:eureka-client【实现服务自动发现与注册】、web【即:springMVC,实现服务API】),POM XML添加配置如下:

      <dependencyManagement>
        <dependencies>
          <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
          </dependency>
        </dependencies>
      </dependencyManagement>
    
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
    
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    
        <!--当.yml配置不生效时,应添加snakeyaml依赖,但一般spring-boot-starter中默认有此依赖,非spring boot项目需要添加-->
        <dependency>
          <groupId>org.yaml</groupId>
          <artifactId>snakeyaml</artifactId>
          <version>1.23</version>
        </dependency>
    
      </dependencies>

      2.2.在application.yml文件中添加如下配置(若没有请参见1.3法创建):注意spring.application.name,这个是服务实例名,注册及服务消费时均需使用该名称

    server:
      port: 8801
    
    spring:
      application:
        name: helloservice
        ip: localhost #自定义配置,在demo代码中有用到
    
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8800/eureka/

      3.3.编写controller 服务相关代码,在spring boot启动类上添加@EnableDiscoveryClient注解,具体完整实现代码如下:(除了@EnableDiscoveryClient注解,基余代码与普通的spring MVC项目代码均相同)

    //controller:
    package cn.zuowenjun.cloud.controller;
    
    import cn.zuowenjun.cloud.model.Result;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.client.discovery.DiscoveryClient;
    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.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class DemoController {
    
        @Value("${spring.application.name}")
        private String serviceName;
    
        @Value("${spring.application.ip}")
        private String address;
    
        @Value("${server.port}")
        private String port;
    
        @Autowired
        DiscoveryClient discoveryClient;
    
    
        @GetMapping(value = "/")
        public String index(){
            return "demo service";
        }
    
        @RequestMapping("/hello")
        public  Object hello(){
            return discoveryClient.getServices();
        }
    
    
        @RequestMapping("/info")
        public Result info(){
            Result result = new Result();
            result.setServiceName(serviceName);
            result.setHost(String.format("%s:%s", address, port));
            result.setMessage("hello");
            return result;
        }
    
        @RequestMapping(value = "/multiply/{a}/{b}")
        public Result multiply(@PathVariable("a") int a,@PathVariable("b") int b){
            Result result = new Result();
            result.setServiceName(serviceName);
            result.setHost(String.format("%s:%s", address, port));
            result.setMessage("ok");
            result.setContent(a * b);
            return result;
        }
    }
    
    //model:
    package cn.zuowenjun.cloud.model;
    
    public class Result {
    
        private int code;
    
        private String message;
    
        private Object content;
    
        private String serviceName;
    
        private String host;
    
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public String getMessage() {
            return message;
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    
        public Object getContent() {
            return content;
        }
    
        public void setContent(Object content) {
            this.content = content;
        }
    
        public String getServiceName() {
            return serviceName;
        }
    
        public void setServiceName(String serviceName) {
            this.serviceName = serviceName;
        }
    
        public String getHost() {
            return host;
        }
    
        public void setHost(String host) {
            this.host = host;
        }
    }
    
    //App spring boot启动类:
    
    package cn.zuowenjun.cloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    @EnableDiscoveryClient
    @SpringBootApplication
    public class App 
    {
        public static void main( String[] args )
        {
            SpringApplication.run(App.class, args);
        }
    }
    View Code

      完成上述步骤后即实现了服务提供者项目,完整项目结构如下图示,启动运行http://localhost:8801/multiply/324/561(只需关注这个服务方法,后面服务消费会调用这个方法) ,可以看到正常响应出JSON结果,如:"code":0,"message":"ok","content":181764,"serviceName":"helloservice","host":"localhost:8801"}

    为了后面服务消费者能体验出负载均衡的效果,可以把该项目再以另一个端口(server.port=8802)重新启动运行一个实例(IDEA启动多个实例的方法请参见:https://blog.csdn.net/forezp/article/details/76408139,最后不一定要改yml中的port配置,也可以直接在Edit Configuration--> program argements中指定:--server.port=8802即可,原理与直接通过命令:java -jar xxx --server.port=8802类似),这样就会有两个服务提供者了,如果查看eureka server主页(http://localhost:8800/)会在Instances currently registered with Eureka列表中展示出2个服务实例信息,如下图示:

    三、实现service consumer(含eureka  client)--服务消费者

    【即:需要调用微服务API的项目,相对eureka,service provider来讲,就是客户端,消费方】,当然也有可能是service provider【服务提供者】,暴露服务API给其它微服务项目

      3.0.参照1.1方式创建一个空的spring boot项目,然后添加spring cloud 相关依赖(这里仅先是:eureka-client【实现服务自动发现与注册】、web【即:springMVC,实现服务API】),POM XML添加配置如下:

        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    View Code

      3.1方式一:使用restTemplate+ribbon实现服务消费(负载均衡调用远程服务)

        3.1.1.在POM XML中添加spring-cloud-starter-netflix-ribbon依赖,如下:

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            </dependency>

        3.1.2.编写controller相关代码(含远程服务调用类HelloService),修改spring boot 启动类,具体完整实现代码如下:

    //spring boot启动类:
    package cn.zuowenjun.cloud;
    
    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;
    
    @EnableDiscoveryClient
    @SpringBootApplication
    class EurekaclientconsumerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(EurekaclientconsumerApplication.class, args);
        }
    
        @LoadBalanced
        @Bean
        public RestTemplate restTemplate(){
            return  new RestTemplate();
        }
    
    }
    
    //controller:
    package cn.zuowenjun.cloud.controller;
    
    import cn.zuowenjun.cloud.service.HelloRemoteService;
    import cn.zuowenjun.cloud.service.HelloService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HelloController {
    
        @Autowired
        private  HelloService helloService;
    
    
        @RequestMapping("/x")
        public Object multiplyForRestTemplate(@RequestParam int a, @RequestParam int b) {
           return   helloService.multiply(a,b);
        }
    
    }
    
    
    //HelloService(远程服务代理类) :
    package cn.zuowenjun.cloud.service;
    
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    
    @Service
    public class HelloService {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @Value("${spring.application.helloServiceProvider}")
        private String  helloServiceName;
    
        public Object multiply(int a,int b){
            String url="http://"+ helloServiceName +"/multiply/" + a +"/" + b;
            return restTemplate.getForObject(url,String.class);
        }
    }
    View Code

     如上代码中最核心的是:HelloService类,通过这个类远程调用【消费】注册在eureka server上对应的服务API,而这个类中最核心的对象是:RestTemplate,而这个又是通过在spring boot启动类(EurekaclientconsumerApplication)中通过代码注入到Spring IOC容器中的(当然也可以自定义一个config类然后统一写BEAN注入的方法),重点请看这个restTemplate Bean注册方法上面的注解:@LoadBalanced,这个就是实现负载均衡(默认是采用轮询的负载均衡算法,还有其它的负载均衡Rule),就这么简单吗?是的,用起来简单,但内部实现还是非常复杂的,Ribbon的运行原理详见:深入理解Ribbon之源码解析,核心思路是:RestTemplate内部维护了一个被@LoadBalance注解的RestTemplate列表,而这些RestTemplate列表又被添加了LoadBalancerInterceptor拦截器,而LoadBalancerInterceptor内部又使用了LoadBalancerClient,而LoadBalancerClient(实现类:RibbonLoadBalancerClient)具体选择服务实例的逻辑又由ILoadBalancer来处理,ILoadBalancer通过配置IRule、IPing等信息,向EurekaClient获取注册列表的信息,并定时向EurekaClient发送“ping”心跳,进而检查是否更新了服务列表,最后得到注册服务实例列表后,ILoadBalancer根据IRule的策略进行负载均衡。

      3.1.3.在application.yml文件中添加如下配置(若没有请参见1.3法创建):

    server:
      port: 8666
    
    spring:
      application:
        name: ribbonclient
        helloServiceProvider: helloservice #自定义配置,指定访问远程服务名称,当然也可以写死在代码中
    
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8800/eureka/ #指向eureka server

    完成上述步骤即实现了一个基于Ribbon的负载均衡服务消费者(客户端)项目。

      3.2方式二:使用feign实现服务消费(负载均衡调用远程服务调用)

      我们仍然基于3.1节原有项目基础上实现基于feign的负载均衡服务调用,注意feign的底层仍然使用了Ribbon。当然也可以单独创一个新的spring boot项目(参照第一节介绍)然后再按下文步骤操作即可。

      3.2.1.在POM XML中添加spring-cloud-starter-openfeign依赖,配置如下:

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
        </dependencies>

      3.2.2.在spring boot启动类(EurekaclientconsumerApplication)上添加:@EnableFeignClients 注解,然后在cn.zuowenjun.cloud.service包中添加自定义HelloRemoteService,这个就是远程服务调用接口类(或称:客户端代理类【接口】),这个就是与3.1中定义的HelloService作用完全类似,只是实现方式不同而矣,最后在controller中添加一个新的API ACTION方法,以便可以调用HelloRemoteService中的服务方法,完整实现代码如下:

    //spring boot启动类
    package cn.zuowenjun.cloud;
    
    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.client.loadbalancer.LoadBalancerAutoConfiguration;
    import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
    
    @EnableDiscoveryClient
    @SpringBootApplication
    @EnableFeignClients(basePackages = "cn.zuowenjun.cloud.service") // 如果启动类不在根目录需要指定basePackages,否则不需要
    class EurekaclientconsumerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(EurekaclientconsumerApplication.class, args);
        }
    
        @LoadBalanced
        @Bean
        public RestTemplate restTemplate(){
            return  new RestTemplate();
        }
    
    }
    
    //HelloRemoteService:
    
    package cn.zuowenjun.cloud.service;
    
    
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.stereotype.Service;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    /*
    *  bug-refer https://blog.csdn.net/zlh313_01/article/details/80309144
    *  bug-refer https://blog.csdn.net/alinyua/article/details/80070890
     */
    @FeignClient(name= "helloservice")
    public interface HelloRemoteService {
    
        @RequestMapping("/multiply/{a}/{b}")
        Object  multiply(@PathVariable("a") int a, @PathVariable("b") int b);
    
    }
    
    //controller:
    
    package cn.zuowenjun.cloud.controller;
    
    import cn.zuowenjun.cloud.service.HelloRemoteService;
    import cn.zuowenjun.cloud.service.HelloService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HelloController {
    
        @Autowired
        private  HelloService helloService;
    
        @Autowired
        private HelloRemoteService helloRemoteService;
    
        @RequestMapping("/x")
        public Object multiplyForRestTemplate(@RequestParam int a, @RequestParam int b) {
           return   helloService.multiply(a,b);
        }
    
        @RequestMapping("/multiply/{a}/{b}")
        public Object multiplyForFeignClient(@PathVariable int a, @PathVariable int b) {
            return helloRemoteService.multiply(a,b);
        }
    }
    View Code

     如上代码HelloRemoteService是重点,需要注意:

    a.必需是interface,因为@FeignClient注解只能用于interface中,而且很显然HelloRemoteService 是远程调用,本地不应有实现的,如果知道原理就更明白这个接口只是为了生成可供restTemplate调用的URL方法而矣;

    b.@FeignClient注解的name(别名属性)或value必填,这个就是需要远程调用服务的应用名称【即:表明消费哪个服务】

    c.接口中定义的方法应与远程服务的controller中的方法保持一致(方法签名,注解),同时注意方法上的一些映射请求的注解,如:@RequestMapping,这些与我们在spring MVC用法相同,但含义却不相同,spring MVC是指处理请求路径,而这里是调用请求路径,这个路径必需与服务提供者API 的对应的ACITON方法上的保持相同,否则将无法成功发送请求。常见问题及解决办法可参见:https://blog.csdn.net/zlh313_01/article/details/80309144

    3.2.3.application.yml配置与3.1.3配置相同,即保持不变即可,最后启动项目即可(现在这个项目同时包含了Ribbon与Feign的负载均衡远程调用服务的方式),通过多次访问:http://localhost:8666/x?a=数字&b=数字 (基于Ribbon实现)、http://localhost:8666/multiply/数字/数字(基于Feign实现)可以看到远程调用服务成功(即:消费服务成功)。

    FeignClient的运行原理详见:深入理解Feign之源码解析,核心思路是:spring boot项目启动时检查@EnableFeignClients,若有则扫描被@FeignClient注解接口并注入到spring IOC容器中,然后在请求被@ FeignCleint标注的接口方法时,会通过JDK动态代理来生成具体的RequesTemplate,RequesTemplate又会生成Request,Request交给Client去处理,最后Client被封装到LoadBalanceClient类,这个类Ribbon中的LoadBalancerClient相同,后面的负载均衡的处理请求相同。

    项目结构及远程调用效果如下图所示:

      

    四、下面分享相关可参考的博文资料链接:

    Spring Cloud之Eureka服务注册与发现(概念原理篇)

    微服务架构:Eureka参数配置项详解(转载)

    Spring Cloud Netflix - Eureka Server源码阅读

    Eureka 参数调优

    提示:本文相关示例项目代码已上传GITHUB,地址如下:

    https://github.com/zuowj/learning-demos/tree/master/java/demo-eurekaserver

    https://github.com/zuowj/learning-demos/tree/master/java/demo-eurekaclient

    https://github.com/zuowj/learning-demos/tree/master/java/demo-eurekaclientconsumer

    说明:文中若有不足之处欢迎指出,码字不易,请多支持,谢谢!

  • 相关阅读:
    linux环境基于python语言docx转pdf
    python pip install XXX出现报错问题
    最干净的pyinstaller打包成exe应用程序方法
    python pyinstaller 打包程序报错解决
    sklearn中predict()与predict_proba()用法区别
    机器学习(数据挖掘十个重要算法)
    在后台管理器上互动,获取后台输入的信息。
    求数组里面最大值,最小值
    数组的排序
    冒泡法的实例(给数组排序)
  • 原文地址:https://www.cnblogs.com/zuowj/p/10408221.html
Copyright © 2011-2022 走看看