provider(提供者)和consumer(使用者)向NacosServer提交注册,然后提供者provider会向消费者提供远端调用服务

在这里插入图片描述

服务注册

 第一步:

在我们创建的nacos项目中的01-sac项目中的sca-provider子项目中对其pom进行jar包的添加

创建微服务项目:微服务01:架构_sayhitoloverOvO的博客-CSDN博客

<?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">
    <parent>
        <artifactId>01-sca</artifactId>
        <groupId>com.jt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>sca-provider</artifactId>
    <dependencies>
        <!--Web服务
        因为在01-sca父类项目中,
        spring boot和alibaba.cloud是被dependencyManagement(依赖配置管理)标签所围绕的,
        所以子类在使用时仍需要重新添加jar包
        -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--服务的注册和发现(我们要讲服务注册到nacos)-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
</project>

Q&A

问:我们在父类01-sca中已经添加过spring boot和alibaba.cloud了为什么此处还要重新添加。如果此处还需要Lombok服务,是否需要添加lombok服务?

答:因为在01-sca父类项目中,spring boot和alibaba.cloud是被dependencyManagement(依赖配置管理)标签所围绕的,所以子类在使用时仍需要重新添加jar包(但是可以不用指定版本了)

而Lombok服务已经被默认添加了,因为它在父类的pom中不被dependencyManagement所标记

详情见:Maven的jar包管理_sayhitoloverOvO的博客-CSDN博客

第二步

修改并配置文件application.yml(或者application.properties)实现服务注册,

.yml文件

server:
  port: 8081  #服务端口默认8080
spring:
  application:
    name: sca-provider    #服务名,假如做服务注册,必须写

  cloud:
    nacos:  #每5s向nacos server发送一次信息,标记该服务还存在
      discovery: #服务的注册和发现
        server-addr: localhost:8848     #nacos server

.properties文件:

server.port: 8081
spring.application.name=sca-provider
spring.cloud.nacos.discovery.server-addr=localhost:8848

注意:服务名不要使用下划线(“_”),应使用横杠(“-”),这是规则。

第三步:

创建启动类,并定义处理请求的控制层对象和方法,关键代码如下:

@SpringBootApplication
public class ProciderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProciderApplication.class, args);
    }
    
    //创建一个内部类模拟执行任务
    @RestController
    public class ProciderController{
        //@value用于动态读取配置文件中的数据
        //要读取的数据写在¥{}的动态表达式中
        //${}表达式中的:后面为表达式默认的数据
        @Value("${server.port:8080}")
        private String server;

        //基于此方法实现一个祖父穿的回显
        //echo,回显
        //rest:一种软件架构的编码风格
        //访问localhost:8081/provider/echo/necos
        @GetMapping("provider/echo/{msg}")
        public String doRestEcho1(@PathVariable("msg") String msg){
            return server+": hello!sayhitolver"+msg;
        }
    }
}

第四步:

先启动nacos服务,微服务02:Nacos_sayhitoloverOvO的博客-CSDN博客

在启动启动类,检测是否服务注册成功,如图所示:

 第五步:

打开浏览器,输入http://localhost:8081/provider/echo/(任意数据),然后进行访问。

nacos中对服务的监展示

服务在yml文件中对nacols进行了配置

spring:
  application:
    name: sca-provider    #服务名
  cloud:
    nacos:  #每5s向nacos server发送一次信息,标记该服务还存在
      discovery: #服务的注册和发现
        server-addr: localhost:8848 #nacos server

nacos收到服务的注册请求后,会在服务列表中创建服务:

 其服务名就是项目中配置文件设定的名字,该名字不可重复

在该配置情况下,会每5s对nacos发送一个信息,标记该服务还在运行 

如果超过15s没有消息被nacos接收到,就会被nacos标记为失联状态,表示该服务不可用

 长期没有回联,那么就会被nacos删除服务,表示该服务已离线

调用入门

第一步:

在我们创建的nacos项目中的01-sac项目中的sca-consumer子项目中对其pom进行jar包的添加

 第二步

编辑yml文件:

server:
  port: 8090  #不写默认8080
spring:
  application:
    name: sca-consumer  #假如做服务注册,必须写
  cloud:
    nacos:  #每5s向nacos server发送一次信息,标记该服务还存在
      discovery: #服务的注册和发现
        server-addr: localhost:8848 #nacos server nacos服务的位置

第三步:

创建启动类,并定义处理请求的控制层对象和方法,关键代码如下:

@SpringBootApplication
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }


    //spring中不包含RestTemplate
    //创建一个RestTemplate对象,并使用@Bean注解将此对象交由Spring管理
    //后续我们会使用这个对象进行远端的调用服务
    @Bean
    public RestTemplate getrestTemplate(){return new RestTemplate();}


    //创建一个内部类模拟执行任务
    @RestController
    public class ConsumerController {

        @Autowired
        private RestTemplate restTemplate;

        //从配置文件动态获取获取appName的数值
        @Value("${spring.application.name:unkownserver}")
        private String appName;

        //使用对应访问的使用方式   一个A对应一个B
        //http://localhost:8090/consumer/echo
        @GetMapping("/consumer/echo")
        public String doRestEcho() {
            //调用服务提供方API(http://lip:port/path)
            //1.定义要调用的API
            String url = "http://localhost:8081/provider/echo/" + appName;
            //2.谁去访问这个API
            return getrestTemplate().getForObject(url, String.class);
        }
        //封装
        //1)侠义:属性私有化,方法能公开就公开
        //2)广义:一个系统有那些服务构成,一个服务有那些模块构成,
        //       一个模块有哪些属性方法构成,
    }       
}

 第四步:

启动浏览器访问消费者服务,通过消费者访问服务端服务

使用LoadBalancerClient,实现负载均衡的调用

消费端可以访问不同的服务端,减少服务端的并发压力

第一步:

修改sca-provider的配置文件端口,分别以8081,8082端口方式进行启动。

创建多个服务端服务,修改pom.xml文件的端口配置:

在这里插入图片描述

 修改并发运行选项(假如没有找到这个选项我们需要通过搜索引擎基于组合查询的方法,去找到对应的解决方案,例如搜索 idea allow parallel run),如图所示:

 修改 端口号,启动多个服务端服务

 启动成功以后,访问nacos的服务列表,检测服务是否成功注册,如图所示:

 第二步:

修改ConsumerController类,注入LoadBalancerClient对象,并添加doRestLoadBalancerClientEcho方法,然后进行服务访问.

    @RestController
    public class ConsumerController {
        //负载均衡的远程服务调用
        //之所以不需要为LoadBalancerClient 配置Bean,
        //是因为Spring Boot/Cloud启动了Ribbon的入口自动配置类
        //该配置类中含有LoadBalancerClient 对象,所以在spring启动时,
        //jar包扫描时会扫描对应配置类,自动创建对应的bean对象实例
        @Autowired
        private LoadBalancerClient loadBalancerClient;


        //负载均衡的使用方式 一个A对应多个B
        //http://localhost:8090/consumer/echo
        @GetMapping("/consumer/echo2")
        public String doRestEcho2() {
            //1.从注册中心获取服务实例
            //2.使用RestTemplate进行服务实例调用
            //使用loadBalancerClient(负载均衡).choose()方法,从服务中心获取服务实例对象
            ServiceInstance instance = loadBalancerClient.choose("sca-provider");
            //使用RestTemplate进行服务实例调用
            String ip = instance.getHost();     //获取该服务的ip地址
            int port = instance.getPort();      //获取该服务的port
            //String url = "http://"+ip+":"+port+"/provider/echo/"+appName;
            //%s占位符,将后方的数值按顺序填充到%s的位置
            String url = String.format( "http://%s:%s/provider/echo/%s"
                    ,ip,port,appName);
            return  getrestTemplate().getForObject(url, String.class);
        }
    }

第三步:

启动sca-consumer项目模块,打开浏览器,输入如下网址进行反复服务访问:

使用@LoadBalanced来实现负载均衡

第一步:

创建一个负载均衡的RestTemplate

利用@LoadBalanced对构建RestTemplate的方法进行修饰

@LoadBalanced注解是属于Spring,而不是Ribbon的,Spring在初始化容器的时候,如果检测到Bean被@LoadBalanced注解,Spring会为其设置LoadBalancerInterceptor的拦截器。

    //spring中不包含RestTemplate
    //创建一个RestTemplate对象,并使用@Bean注解将此对象交由Spring管理
    //后续我们会使用这个对象进行远端的调用服务
    //不包含负载均衡功能的RestTemplate 
    @Bean    //bean的名称是getrestTemplate()
    public RestTemplate getrestTemplate(){return new RestTemplate();}

    //包含负载均衡功能的RestTemplate 
    @LoadBalanced
    @Bean     //bean的名称是LoadBalancerClientRestTemplate()
    public RestTemplate LoadBalancerClientRestTemplate(){return new RestTemplate();}

 在需要RestTemplate实现负载均衡调用的地方进行依赖注入.例如在ConsumerController类中添加loadBalancedRestTemplate属性

        //包含负载均衡功能的RestTemplate 
        @Autowired
        private RestTemplate getrestTemplate;

        //包含负载均衡功能的RestTemplate 
        @Autowired
        private RestTemplate LoadBalancerClientRestTemplate;

Q:怎么避免两个相同类型的bean发生冲突?

A:@Autowired会先根据类型匹配bean对象,如果类型相同,那么会匹配bean对象的名称检查是否相同。在该场景中两个bean类型相同,spring会根据接下来的对象名进行匹配确定最终的唯一结果,如果结果唯一,不会报错,结果不唯一,会报错。

  @GetMapping("/consumer/echo3")
        public String doRestEcho3() {
            String url = String.format( "http://%s/provider/echo/%s"
                ,"sca-provider",appName);
            return LoadBalancerClientRestTemplate.getForObject(url, String.class);
        }    

 利用包含自动均衡特性的RestTemplate,获取对应的服务("sca-provider")的ip,port。填充到url种进行方法的处理。

RestTemplate在发送请求的时候会被LoadBalancerInterceptor拦截,它的作用就是用于RestTemplate的负载均衡,LoadBalancerInterceptor将负载均衡的核心逻辑交给了loadBalancer,核心代码如下所示(了解):

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐