【Nacos】服务注册

288 阅读2分钟

这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战

一、服务注册 - Provider 搭建

Nacos docker 启动,版本 1.3.2 spring boot 版本 2.2.1.RELEASE spring cloud alibaba 版本 2.2.0.RELEASE

  1. pom.xml
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
​
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
​
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
  1. 配置文件
spring.application.name=my-provider
server.port=8080
spring.cloud.nacos.discovery.server-addr=192.168.226.36:8848
  1. 代码
@SpringBootApplication
public class NacosProviderApplication {
​
    public static void main(String[] args) {
        SpringApplication.run(NacosProviderApplication.class, args);
    }
​
    @RestController
    class EchoController {
​
        @GetMapping("/echo")
        public String echo(HttpServletRequest request) {
            return "echo: " + request.getParameter("name");
        }
    }
​
}

启动后,服务正常。

可以查看 Nacos,服务发现,如图:

2021-01-1817-22-54.png



二、服务发现 - Consumer 搭建

  1. pom配置,如同 provider
  1. 配置文件
spring.application.name=nacos-consumer
server.port=8081
spring.cloud.nacos.discovery.server-addr=localhost:8848
  1. 代码
@SpringBootApplication
@EnableDiscoveryClient(autoRegister = false) // 设置不自动注册到注册中心
public class NacosConsumerApplication {
​
    public static void main(String[] args) {
        SpringApplication.run(NacosConsumerApplication.class, args);
    }
​
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
​
    @RestController
    class HelloController {
​
        @Autowired
        private DiscoveryClient discoveryClient; // 服务发现
​
        @Autowired
        private RestTemplate restTemplate;
​
        private String serviceName = "my-provider";
​
        @GetMapping("/info")
        public String info() {
            // 使用 DiscoveryClient 获取 my-provider 服务对应的所有实例
            List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serviceName);
            StringBuilder sb = new StringBuilder();
            sb.append("All services: " + discoveryClient.getServices() + "<br/>");
            sb.append("my-provider instance list: <br/>");
            serviceInstances.forEach(instance -> {
                sb.append("[ serviceId: " + instance.getServiceId() +
                        ", host: " + instance.getHost() +
                        ", port: " + instance.getPort() + " ]");
                sb.append("<br/>");
            });
            return sb.toString();
        }
​
        @GetMapping("/hello")
        public String hello() {
            List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serviceName);
            ServiceInstance serviceInstance = serviceInstances.stream()
                    .findAny().orElseThrow(() ->
                            new IllegalStateException("no " + serviceName + " instance available"));
            return restTemplate.getForObject(
                    "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() +
                            "/echo?name=nacos", String.class);
        }
​
    }
}

访问 http://localhost:8081/info:

All services: [my-provider]
my-provider instance list:
[ serviceId: my-provider, host: 192.168.226.36, port: 8080 ]

访问 http://localhost:8081/hello:

echo: nacos



三、配置管理 - Provider 搭建

在 一、服务 - Provider 搭建 的基础上,搭建。

  1. pom.xml 中添加
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
  1. 在 resources 添加 bootstrap.properties
spring.application.name=my-provider
server.port=8080
spring.cloud.nacos.config.server-addr=192.168.226.36:8848
spring.cloud.nacos.discovery.server-addr=192.168.226.36:8848
  1. 在 NacosProviderApplication.java 中添加代码
@SpringBootApplication
public class NacosProviderApplication {
​
    public static void main(String[] args) {
        SpringApplication.run(NacosProviderApplication.class, args);
    }
​
    @RestController
    class EchoController {
​
        @Autowired
        ApplicationContext applicationContext;
​
        @GetMapping("/echo")
        public String echo(HttpServletRequest request) {
            return "echo: " + request.getParameter("name");
        }
​
        // 添加如下
        @GetMapping("/config")
        public String config() {
​
            return "env.get('book.category')=" +
                    applicationContext.getEnvironment().getProperty("book.category", "unknown");
        }
    }
​
}
  1. 在 Nacos 里新建配置,并发布。 如图:2021-01-1817-22-54

启动服务,服务运行正常。

访问 http://localhost:8080/config :

env.get('book.category')=spring cloud

修改Nacos 里的配置文件,访问 http://localhost:8080/config:

可以发现配置动态更新了。

env.get('book.category')=spring cloud nacos

bootstrap.properties 文件,该文件配置了 Nacos 配置中心的地址,这个文件会让 Spring Cloud 启动 Bootstrap 阶段在 Nacos 配置中心获取配置。

Spring Cloud 的 Bootstrap 阶段的概念:

在 Bootstrap 阶段会构造 ApplicationContext,这个ApplicationContext 加载配置的过程会基于 bootstrap.properties 或 bootstrap.yaml 文件(spring.config.name 为 bootstrap)去加载文件。 在加载文件的过程中,Spring Cloud 有一套机制(PropertySourceLocator 接口的定义)来u构造数据源 PropertySource,其余跟 Spring Boot 一致的。

BootStrap 阶段构造的 ApplicationContext 会作为正常阶段的 ApplicationContext 的父类(parent),有了这一层父子关系之后,如果不能从子 ApplicationContext 获取配置,就会从父 ApplicationContext 获取。

Spring Cloud Bootstrap 阶段优先级高,会先读取配置中心的配置,这些配置在下一次正常的 ApplicationContext 启动时作用。

spring-cloud-context 模块内部的 META-INF/spring.factories 添加了一个 Bootstrap-ApplicationListener (实现了 ApplicationListener 接口),用于监听 ApplicationEnvironmentPreparedEvent 事件(Environment 刚创建,ApplicationContext 未创建时会触发事件),收到该事件后进入 Bootstrap 阶段,从配置中心加载配置。