SpringCloud - Spring Cloud Alibaba 之 Nacos Discovery服务注册发现(三)

阅读本文可先参考博文

https://blog.csdn.net/MinggeQingchun/article/details/125613600

https://blog.csdn.net/MinggeQingchun/article/details/125614065

一、Nacos Discovery服务注册发现

1、服务提供者

1、 创建一个springboot模块springcloud-alibaba-1-nacos-discovery-provider;

2、 添加spring-cloud-starter-alibaba-nacos-discovery等依赖;

(1)通过添加一个starter依赖:spring-cloud-starter-alibaba-nacos-discovery它通过自动配置、注解以及Spring Boot 编程模型与Nacos无缝集成,实现服务注册与发现

<!--spring-cloud-alibaba nacos服务注册/发现的依赖-->
        <!--格式: spring-cloud-starter-[开源组织机构名字]-[项目模块名字]-->
        <!--spring-cloud-starter-alibaba-sentinel-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

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

(2)Spring Cloud Alibaba 和 Spring Cloud,Spring Boot对应版本

在该工程的 pom.xml 中,我们通过 dependencyManagement 对 Spring Cloud Alibaba 的版本信息进行管理,该工程下的各个子模块在引入 Spring Cloud Alibaba 的各个组件时就不要单独指定版本号了

<properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.12.RELEASE</spring-boot.version>
        <spring-cloud-alibaba.version>2.2.7.RELEASE</spring-cloud-alibaba.version>
</properties>
<!-- dependencyManagement标签 通常适用于多模块环境下定义一个top module来专门管理公共依赖的情况
        在子项目中不写该依赖项,那么子项目仍然会从父项目depenManagement中继承该artifactId和groupId依赖项(全部继承)
        若子项目 中dependencies中的dependency声明了version,则父项目中dependencyManagement中的声明无效

        Spring Cloud、Spring Cloud Alibaba 以及 Spring Boot 之间版本依赖参考官网
        https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
    -->
    <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>
            <!-- spring-cloud-dependencies -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR12</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

完整POM文件如下

<modelVersion>4.0.0</modelVersion>

    <groupId>com.company</groupId>
    <artifactId>springcloud-alibaba-1-nacos-discovery-provider</artifactId>
    <version>1.0.0</version>

    <name>springcloud-alibaba-1-nacos-discovery-provider</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.12.RELEASE</spring-boot.version>
        <spring-cloud-alibaba.version>2.2.7.RELEASE</spring-cloud-alibaba.version>
    </properties>

    <dependencies>
        <!--spring boot web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--spring-cloud-alibaba nacos服务注册/发现的依赖-->
        <!--格式: spring-cloud-starter-[开源组织机构名字]-[项目模块名字]-->
        <!--spring-cloud-starter-alibaba-sentinel-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

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

        <dependency>
            <groupId>com.company</groupId>
            <artifactId>springcloud-alibaba-1-commons</artifactId>
            <version>1.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- springboot 开发自动热部署 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- MySQL的jdbc驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--mybatis起步依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>

    <!-- dependencyManagement标签 通常适用于多模块环境下定义一个top module来专门管理公共依赖的情况
        在子项目中不写该依赖项,那么子项目仍然会从父项目depenManagement中继承该artifactId和groupId依赖项(全部继承)
        若子项目 中dependencies中的dependency声明了version,则父项目中dependencyManagement中的声明无效

        Spring Cloud、Spring Cloud Alibaba 以及 Spring Boot 之间版本依赖参考官网
        https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
    -->
    <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>
            <!-- spring-cloud-dependencies -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR12</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!--mybatis代码自动生成插件-->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.4.0</version>
                <configuration>
                    <!--配置文件的位置-->
                    <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
                    <!--生成代码过程中是否打印日志-->
                    <verbose>true</verbose>
                    <!--生成时是否覆盖java文件,xml文件总是合并-->
                    <overwrite>true</overwrite>
                </configuration>
            </plugin>
        </plugins>

        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
    </build>

3、 在应用的/src/main/resources/application.properties(也可以是application.yaml)配置文件中配置NacosServer地址,如果不想使用Nacos作为您的服务注册与发现,可以将spring.cloud.nacos.discovery.enabled设置为false;

#内嵌的web服务器端口
server.port=9001

#服务名称
spring.application.name=springcloud-alibaba-1-nacos-discovery-provider

#设置mysql数据库连接信息
spring.datasource.url=jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=admin123456

#将Nacos设置为服务注册发现,默认为true
spring.cloud.nacos.discovery.enabled=true
#nacos注册中心的连接地址
spring.cloud.nacos.discovery.server-addr=192.168.133.129:8848

#nacos的用户名和密码
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos

#spring boot actuator 监控和健康检查功能
management.endpoints.jmx.exposure.include=*
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always

4、 在SpringBoot启动类加上**@EnableDiscoveryClient**注解;

@EnableDiscoveryClient //开启服务注册与发现功能: classpath: META-INF/spring.factories文件
@SpringBootApplication
public class Alibaba1NacosDiscoveryProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(Alibaba1NacosDiscoveryProviderApplication.class, args);
    }
}

 

5、 编写controller测试类;

@Slf4j
@RestController
public class EchoController {

    @GetMapping("/")
    public ResponseEntity index() {
        log.info("provider /");
        return new ResponseEntity("index", HttpStatus.OK);
    }
    @GetMapping("/divide")
    public String divide(@RequestParam Integer a, @RequestParam Integer b) {
        log.info("provider /divide");
        return String.valueOf(a / b);
    }

    @GetMapping("/notFound")
    public String notFound() {
        System.out.println("provider 1 .........");
        return "notFound";
    }
}

6、 启动Nacos服务,启动main类,在nacos服务台上查看服务;

 

点击详情查看 

2、服务消费者

1、 新建服务消费者模块springcloud-alibaba-1-nacos-discovery-consumer;

2、 添加spring-cloud-starter-alibaba-nacos-discovery,spring-cloud-loadbalancer等;

依赖

<!--spring boot web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- springboot官方依赖: spring-boot-starter-xxx-->
        <!-- springboot非官方依赖:xxx-spring-boot-starter-->

        <!--springcloud依赖:spring-cloud-starter-xxx -->
        <!--spring-cloud-alibaba 服务注册发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

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

        <!--由于 Netflix Ribbon 进入停更维护阶段,因此新版本的 Nacos discovery 都已经移除了 Ribbon ,
            此时我们需要引入 loadbalancer 代替,才能调用服务提供者提供的服务
        -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>

注:

由于Netflix Ribbon 在2020版 进入停更维护阶段,因此新版本的 Nacos discovery 都已经移除了 Ribbon , 此时我们需要引入 loadbalancer 代替,才能调用服务提供者提供的服务

<groupId>com.company</groupId>
    <artifactId>springcloud-alibaba-1-nacos-discovery-consumer</artifactId>
    <version>1.0.0</version>

    <name>springcloud-alibaba-1-nacos-discovery-consumer</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.12.RELEASE</spring-boot.version>
        <spring-cloud-alibaba.version>2.2.7.RELEASE</spring-cloud-alibaba.version>
    </properties>

    <dependencies>
        <!--spring boot web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- springboot官方依赖: spring-boot-starter-xxx-->
        <!-- springboot非官方依赖:xxx-spring-boot-starter-->

        <!--springcloud依赖:spring-cloud-starter-xxx -->
        <!--spring-cloud-alibaba 服务注册发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

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

        <!--由于 Netflix Ribbon 进入停更维护阶段,因此新版本的 Nacos discovery 都已经移除了 Ribbon ,
            此时我们需要引入 loadbalancer 代替,才能调用服务提供者提供的服务
        -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>

        <dependency>
            <groupId>com.company</groupId>
            <artifactId>springcloud-alibaba-1-commons</artifactId>
            <version>1.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <!-- dependencyManagement标签 通常适用于多模块环境下定义一个top module来专门管理公共依赖的情况
        在子项目中不写该依赖项,那么子项目仍然会从父项目depenManagement中继承该artifactId和groupId依赖项(全部继承)
        若子项目 中dependencies中的dependency声明了version,则父项目中dependencyManagement中的声明无效

        Spring Cloud、Spring Cloud Alibaba 以及 Spring Boot 之间版本依赖参考官网
        https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
    -->
    <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>
            <!-- spring-cloud-dependencies -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR12</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

        </plugins>
    </build>

3、 在应用的/src/main/resources/application.properties(也可以是application.yaml)配置文件中配置NacosServer地址,如果不想使用Nacos作为您的服务注册与发现,可以将spring.cloud.nacos.discovery.enabled设置为false;

#内嵌的web服务器端口
server.port=8081

#服务名称
spring.application.name=springcloud-alibaba-1-nacos-discovery-consumer

#将Nacos设置为服务注册发现,默认为true
spring.cloud.nacos.discovery.enabled=true
#nacos注册中心的连接地址
spring.cloud.nacos.discovery.server-addr=192.168.133.129:8848

#nacos的用户名和密码
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos

#spring boot actuator 监控和健康检查功能
management.endpoints.jmx.exposure.include=*
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always

#自定义配置,远程服务提供者的服务名
service.name=http://springcloud-alibaba-1-nacos-discovery-provider

#避免The bean 'springcloud-alibaba-1-nacos-discovery-provider.FeignClientSpecification' could not be registered. A bean with that name has already been defined and overriding is disabled.
spring.main.allow-bean-definition-overriding=true

注:

springboot bean覆盖注册的问题 allowBeanDefinitionOverriding 配置

项目引用三方jar包,需要对@Configuration配置类中的某个bean进行重写。过程中遇到了bean已被注册异常、以及新加的bean不加载

***************************
APPLICATION FAILED TO START
***************************

Description:

The bean 'springcloud-alibaba-1-nacos-discovery-provider.FeignClientSpecification' could not be registered. A bean with that name has already been defined and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

Disconnected from the target VM, address: '127.0.0.1:56743', transport: 'socket'

  在项目中定义了两个 Feign 客户端 ,两个 Feign 客户端中配置的 value 值是一样的 导致在启动时报如上错误

设置spring.main.allow-bean-definition-overriding=true 即可

4、 在SpringBoot启动类加上**@EnableDiscoveryClient**注解;

@EnableFeignClients //开启feign
@EnableDiscoveryClient //开启nacos服务注册与发现
@SpringBootApplication
public class Alibaba1NacosDiscoveryConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(Alibaba1NacosDiscoveryConsumerApplication.class, args);
    }
}

5、 编写测试类controller;


@RestController
public class TestController {

	@Autowired
	private LoadBalancerClient loadBalancerClient;

	@Autowired
	private RestTemplate restTemplate;

	//feign 的声明式调用
	@Autowired
	private EchoFeignService echoFeignService;

	@Autowired
	private DiscoveryClient discoveryClient;

	@GetMapping("/echo/{app}")
	public String echoAppName(@PathVariable("app") String app){
		//使用 LoadBalanceClient 和 RestTemplate 结合的方式来访问
		ServiceInstance serviceInstance = loadBalancerClient.choose("springcloud-alibaba-1-nacos-discovery-provider");

		//  http://192.168.0.104:18082/echo/{app}
		String url = String.format("http://%s:%s/echo/%s", serviceInstance.getHost(), serviceInstance.getPort(), app);
		System.out.println("request url:"+url);

		return restTemplate.getForObject(url, String.class);
	}
	@GetMapping("/notFound-feign")
	public String notFound() {
		return echoFeignService.notFound();
	}

	@GetMapping("/divide-feign")
	public String divide(@RequestParam Integer a, @RequestParam Integer b) {
		return echoFeignService.divide(a, b);
	}

	@GetMapping("/divide-feign2")
	public String divide(@RequestParam Integer a) {
		return echoFeignService.divide(a);
	}

	@GetMapping("/echo-feign/{str}")
	public String feign(@PathVariable String str) {
		return echoFeignService.echo(str);
	}

	@GetMapping("/services/{service}")
	public Object client(@PathVariable String service) {
		return discoveryClient.getInstances(service);
	}

	@GetMapping("/services")
	public Object services() {
		System.out.println(discoveryClient.description());
		System.out.println(discoveryClient.getOrder());
		return discoveryClient.getServices();
	}
}
@Configuration
public class MyRibbonConfig {

//    @SentinelRestTemplate(/*blockHandler="blockA", blockHandlerClass= MyBlockHandlerClass.class*/ //限流
//            fallback="fallbackA", fallbackClass = MyBlockHandlerClass.class) // 降级
    @Bean
    @LoadBalanced //与 Ribbon 集成,并开启负载均衡功能
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

EchoFeignService

@FeignClient(name = "springcloud-alibaba-1-nacos-discovery-provider",
        fallbackFactory = EchoFeignServiceFallbackFactory.class,
        configuration = FeignConfiguration.class)
public interface EchoFeignService {

    @GetMapping("/echo/hello")
    default String hello() {
        return "hello";
    }

    @GetMapping("/echo/{str}")
    String echo(@PathVariable("str") String str);

    @GetMapping("/divide")
    String divide(@RequestParam("a") Integer a, @RequestParam("b") Integer b);

    /**
     * feign声明的接口可以有默认实现, 就是可以不需要远程服务提供者实现,自己实现了
     *
     * @param a
     * @return
     */
    default String divide(Integer a) {
        System.out.println("consumer devide method......");
        return divide(a, 1);
    }

    // restTemplate.getForObject("http://springcloud-alibaba-1-nacos-discovery-provider/sleep", String.class);

    // @FeignClient(name = "springcloud-alibaba-1-nacos-discovery-provider")
    // http://springcloud-alibaba-1-nacos-discovery-provider/notFound

    @GetMapping("/notFound")
    String notFound();
}
EchoFeignServiceFallbackFactory

public class EchoFeignServiceFallbackFactory implements FallbackFactory<EchoFeignService> {

    @Override
    public EchoFeignService create(Throwable throwable) {
        return new EchoFeignService() {
            @Override
            public String hello() {
                return "hello fall back" + throwable.getMessage();
            }

            @Override
            public String echo(@PathVariable("str") String str) {
                return "echo fallback" + throwable.getMessage();
            }

            @Override
            public String divide(@RequestParam Integer a, @RequestParam Integer b) {
                return "divide fallback" + throwable.getMessage();
            }

            @Override
            public String divide(Integer a) {
                return "divide fall back" + throwable.getMessage();
            }

            @Override
            public String notFound() {
                return "default feign invoke notFound fallback 999" + throwable.getMessage();
            }
        };
    }
}
FeignConfiguration

public class FeignConfiguration {

    @Bean
    public EchoFeignServiceFallbackFactory echoFeignServiceFallbackFactory() {
        return new EchoFeignServiceFallbackFactory();
    }
}

6、 启动Nacos服务,启动main类,在nacos服务台上查看服务;

http://localhost:8081/divide-feign?a=10&b=2

 

 

注:

Nacos注册中心宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表

版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: