2 Eureka注册中心

1 Eureka 简介

  Spring Cloud Eureka 是 Spring Cloud Netflix 微服务条件的一部分,基于 Netflix Eureka 做了二次封装,主要负责实现微服务脚骨中的服务治理功能。Spring Cloud Eureka 是一个基于 REST 的服务,并且提供了基于 Java 的客户端组件,能够非常方便地将服务注册到 Spring Cloud Eureka 中进行统一管理。
  除了用 Eureka 作为注册中心外,我们还可以使用 Consul、Etcd、Zookeeper 等来作为服务的注册中心。
用过 Dubbo 的应该清楚,Dubbo 中也有几种注册中心,比如基于 Zookeeper 的、基于 Redis 的等。至于使用哪种方式都是可以的。

2 选型

  接下来对 Eureka 和 Zookeeper 作比较。
  Eureka 是基于 AP 原则构建的,而 Zookeeper 是基于 CP 原则构建的。在分布式系统领域有个著名的 CAP 定理,即 C 为数据一致性;A 为服务可用性;P 为服务队网络分区故障的容错性。这三个特性在任何分布式系统中都不可能同时满足,最多同时满足两个。
  Zookeeper 有一个 Leader,而且在 Leader 无法使用的时候通过 Paxos(ZAB)算法选举出一个新的 Leader。这个 Leader 的任务就是保证写数据的时候只向这个 Leader 写入,Leader 会同步信息到其他节点。通过这个操作就可以保证数据的一致性。
  总而言之,想要保证 AP 就要用 Eureka,想要保证 CP 就要用 Zookeeper。Dubbo 中大部分都是基于 Zookeeper 作为注册中心的。Spring Cloud 中当然首选 Eureka。

注意:2018 年 12 月 12 日,Netflix 宣布 Spring Cloud Netflix 系列技术栈进入维护模式(不再添加新特性),至于为什么要学 Netflix,是因为通过它来理解微服务,Spring Cloud Alibaba 也是一种新的微服务解决方案,两者使用起来差不多。

3 实现 Eureka 注册中心
3.1 创建统一的依赖管理

  先创建一个文件夹名为 spring-cloud,通过 IDEA 打开,然后在该文件夹下创建一个工程名为 spring-cloud-dependencies 的项目,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>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
    </parent>

    <groupId>com.pky</groupId>
    <artifactId>spring-cloud-dependencies</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <!-- 表示该项目仅当做依赖项目,没有具体的实现代码 -->
    <packaging>pom</packaging>

    <name>spring-cloud-dependencies</name>

    <properties>
        <!-- Environment Settings -->
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

        <!-- Spring Settings -->
        <spring-cloud.version>Finchley.RC1</spring-cloud.version>
    </properties>

    <!-- 在 properties 配置中预定义了版本号为 Finchley.RC1 ,表示我们的 Spring Cloud 使用的是 F 版 -->
    <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>

    <!-- 配置了项目所需的各种插件 -->
    <build>
        <plugins>
            <!-- Compiler 插件, 设定 JDK 版本 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <showWarnings>true</showWarnings>
                </configuration>
            </plugin>

            <!-- 打包 jar 文件时,配置 manifest 文件,加入 lib 包的 jar 依赖 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <addMavenDescriptor>false</addMavenDescriptor>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <configuration>
                            <archive>
                                <manifest>
                                    <!-- Add directory entries -->
                                    <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                                    <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                                    <addClasspath>true</addClasspath>
                                </manifest>
                            </archive>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!-- resource -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
            </plugin>

            <!-- install -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-install-plugin</artifactId>
            </plugin>

            <!-- clean -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-clean-plugin</artifactId>
            </plugin>

            <!-- ant -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
            </plugin>

            <!-- dependency -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
            </plugin>
        </plugins>

        <pluginManagement>
            <plugins>
                <!-- Java Document Generate -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-javadoc-plugin</artifactId>
                    <executions>
                        <execution>
                            <phase>prepare-package</phase>
                            <goals>
                                <goal>jar</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>

                <!-- YUI Compressor (CSS/JS压缩) -->
                <plugin>
                    <groupId>net.alchim31.maven</groupId>
                    <artifactId>yuicompressor-maven-plugin</artifactId>
                    <version>1.5.1</version>
                    <executions>
                        <execution>
                            <phase>prepare-package</phase>
                            <goals>
                                <goal>compress</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <encoding>UTF-8</encoding>
                        <jswarn>false</jswarn>
                        <nosuffix>true</nosuffix>
                        <linebreakpos>30000</linebreakpos>
                        <force>true</force>
                        <includes>
                            <include>**/*.js</include>
                            <include>**/*.css</include>
                        </includes>
                        <excludes>
                            <exclude>**/*.min.js</exclude>
                            <exclude>**/*.min.css</exclude>
                        </excludes>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>

        <!-- 资源文件配置 -->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <excludes>
                    <exclude>**/*.java</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
        </resources>
    </build>

    <!-- 配置项目下载依赖时的第三方库 -->
    <repositories>
        <repository>
            <id>aliyun-repos</id>
            <name>Aliyun Repository</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>

        <repository>
            <id>sonatype-repos</id>
            <name>Sonatype Repository</name>
            <url>https://oss.sonatype.org/content/groups/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>sonatype-repos-s</id>
            <name>Sonatype Repository</name>
            <url>https://oss.sonatype.org/content/repositories/snapshots</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>

        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>aliyun-repos</id>
            <name>Aliyun Repository</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
</project>

注意:spring boot 版本号需要和spring cloud 版本对应,否则不兼容。版本的对应可以查看上一篇文章

3.2 编写 Eureka 注册中心服务
  • 创建一个工程名为 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>

    <parent>
        <groupId>com.pky</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../spring-cloud-dependencies/pom.xml</relativePath>
    </parent>

    <artifactId>spring-cloud-eureka</artifactId>
    <packaging>jar</packaging>

    <name>spring-cloud-eureka</name>

    <dependencies>
        <!-- Spring Boot Begin -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot End -->

        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- Spring Cloud End -->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.pky.spring.cloud.eureka.EurekaApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
  • 在 src/main/java 下创建包 com.pky.spring.cloud.eureka,并创建启动类 EurekaApplication
package com.pky.spring.cloud.eureka;


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

@SpringBootApplication
@EnableEurekaServer  //开启服务注册与发现
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}
  • 在 src/main/resources 下创建一个 application.yml 配置文件,添加如下配置信息:
spring:
  application:
    name: spring-cloud-eureka
# 端口号
server:
  port: 9501

eureka:
  # eureak实例定义
  instance:
    # 定义 Eureka 实例所在的主机名称
    hostname: localhost
  client:
    # 由于该应用为注册中心,所以设置为 false,代表不向注册中心注册自己
    register-with-eureka: false
    # 由于注册中心的职责就是维护服务实例,他并不需要去检索服务,所以也设置为 false
    fetch-registry: false
    # 客户端的默认地址
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka

注意: eureka.client.register-with-eureka 一定要为 false,不然启动时会把自己当做客户端向自己注册,会报错。

  • 运行,浏览器输入: http://localhost:9501 ,eureka 界面如下:
    在这里插入图片描述
4 编写服务提供者

  注册中心已经创建并启动成功好了,接下来实现一个服务提供者 spring-cloud-service-admin-provider,注册到Eureka中,并提供一个接口给其他服务调用。

  • 创建一个工程名为 spring-cloud-service-admin-provider 的项目,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>

    <parent>
        <groupId>com.pky</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../spring-cloud-dependencies/pom.xml</relativePath>
    </parent>

    <artifactId>spring-cloud-service-admin-provider</artifactId>
    <packaging>jar</packaging>

    <name>spring-cloud-service-admin-provider</name>

    <dependencies>
        <!-- Spring Boot Begin -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot End -->

        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- Spring Cloud End -->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.pky.spring.cloud.service.admin.AdminProviderApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
  • 启动类 AdminProviderApplication
package com.pky.spring.cloud.service.admin;

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

@SpringBootApplication
@EnableEurekaClient  // 表明当前服务是 eureka 的一个客户端
public class AdminProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(AdminProviderApplication.class);
    }
}

启动类的方法与之前没有多大区别,就是注解变了,换成了 @EnableEurekaClient,这个表示当前服务是一个 Eureka 的客户端。

  • application.yml
spring:
  application:
    name: admin-provider
# 端口号
server:
  port: 9502

eureka:
  client:
    service-url:
      defaultZone : http://localhost:9501/eureka

eureka.client.serviceUrl.defaultZone 的地址就是我们之前启动的 Erueka 服务的地址,在启动的时候需要将自身的信息注册到 Eureka 中去。

  • 启动服务,会看到 erueka 界面中多了刚刚启动的服务,如下图:
    在这里插入图片描述
  • 编写服务提供接口 TestProviderController
package com.pky.spring.cloud.service.admin.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(value = "admin")
public class TestProviderController {

    @Value("${server.port}")
    String port;

    @PostMapping(value = "")
    public String adminTest(){
        return String.format("hello, I'm service admin from port :%s",port);
    }
}

  重启服务,通过访问 http://localhost:9502/admin ,如果能看到返回的 “hello, I’m service admin from port :9502” 字符串,就证明接口提供成功了。

5 编写服务消费者
5.1 直接调用接口

  创建服务消费者,消费我们刚刚写的 admin 接口。同样还需要创建一个 Maven 项目 spring-cloud-service-admin-consumer,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>

    <parent>
        <groupId>com.pky</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../spring-cloud-dependencies/pom.xml</relativePath>
    </parent>

    <artifactId>spring-cloud-service-admin-consumer</artifactId>
    <packaging>jar</packaging>

    <name>spring-cloud-service-admin-consumer</name>

    <dependencies>
        <!-- Spring Boot Begin -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot End -->

        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- Spring Cloud End -->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.pky.spring.cloud.service.admin.consumer.AdminConsumerApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

  AdminConsumerApplication 启动类

@SpringBootApplication
@EnableEurekaClient
public class AdminConsumerApplication {

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

  RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程 Http 服务的方法,能够大大提高客户端的编写效率。我们通过配置 RestTemplate 来调用接口,创建一个 config 包并创建 BeanConfiguration 配置类:

package com.pky.spring.cloud.service.admin.consumer.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class BeanConfiguration {

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

  创建接口,在接口中调用 admin 接口,创建controller 包,并创建 TestConsumerController 控制器,如下:

package com.pky.spring.cloud.service.admin.consumer.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping(value = "admin_consumer")
public class TestConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping(value = "")
    public String testAdminConsumer() {
        return restTemplate.getForObject("http://localhost:9502/admin", String.class);
    }
}

  启动该服务,访问 http://localhost:9503/admin_consumer ,如果能看到返回的 “hello, I’m service admin from port :9502” 字符串,就证明接口消费成功了。

5.2 通过 Eureka 来消费接口

  上面我们是直接通过服务接口的地址来调用的,这样和我们之前的做法就是一样的了,完全没有用到 Eureka 带给我们的便利。既然使用了注册中心,那么客户端调用哪个的时候肯定是不需要关心有多少个服务提供接口,下面来改造一下之前的调用代码。
  首先改造 RestTemplate 的配置,添加一个 @LoadBalanced 注解,这个注解会自动构造 LoadBalancerClient 接口的实现类并注册到 Spring 容器中,如下:

package com.pky.spring.cloud.service.admin.consumer.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 BeanConfiguration {

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

  接下来是改造调用代码,我们不再直接写固定地址,而是改成服务的名称,这个名称就是我们注册到 Eureka 中的名称,是属于文件中 spring.application.name,调用代码如下:

package com.pky.spring.cloud.service.admin.consumer.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping(value = "admin_consumer")
public class TestConsumerController {

   @Autowired
   private RestTemplate restTemplate;

   @GetMapping(value = "")
   public String testAdminConsumer() {
       return restTemplate.getForObject("http://admin-provider/admin", String.class);
   }
}
6 开启 Eureka 认证

  Eureka 自带了一个 Web 的管理页面,方便我们查询注册到上面的示例信息,但是有一个问题:如果在实际使用中,注册中心地址有公网 IP 的话,必然能直接访问到,这样是不安全的。所以我们需要对 Eureka 进行改造,加上权限认证来保证安全性。
  改造 spring-cloud-eureka 项目,通过继承 Spring-Security 来进行安全认证,添加其依赖到 pom.xml 中

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

  appilication.yml 中添加配置信息

spring:
	security:
		name: pky
		password: 123

注意:当前 Spring Cloud 版本为 2.0 以上版本,如果是 2.0 以下版本,配置如下:

security:
	basic:
		enabled: true # 开启认证
	user:
		name: pky
		password: 123

  2.0 以上版本还需要关闭 SpringSecurity 的跨域保护。SpringSecurity 默认开启跨域保护,在学习 SpringCloud 的时候,要运行很多个服务,每个服务的端口不一致,所以造成了跨域,SpringSecurity 就不会让你访问到注册中心了。创建 config 包并创建 SecurityConfig 类继承 WebSecurityConfigurerAdapter,代码如下:

package com.pky.spring.cloud.eureka.config;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();  // 关闭跨域保护 
        super.configure(http);
    }
}

如果不关闭,会出现 com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server 的异常

  重新启动注册中心,访问 http://localhost:9501/ ,此时浏览器会提示要输入用户名和密码。

  在 Eureka 认证后,客户端注册的配置也要加上认证的用户名和密码信息:

eureka:
  client:
    service-url:
      defaultZone : http://pky:123@localhost:9501/eureka
7 Eureka 高可用搭建
7.1 高可用原理

  前面搭建的注册中心只适合本地开发使用,在生产环境中必须搭建一个集群来保证高可用。Eureka 的集群搭建方法很简单:每一台 Eureka 只需要在配置中指定另外多个 Eureka 的地址就可以实现一个集群的搭建了。
  假设有 master 和 slaveone 两台机器,需要做的就是:

  • 将 master 注册到 slaveone 上面。
  • 将 slaveone 注册到 master 上面。

  如果是 3 台机器,依次类推

7.2 搭建步骤

  首先我们需要添加 2 个属性文件,通过不同的环境来启动不同的实例。

  • 添加 application-master.yml

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值