服务注册与调用

服务注册与调用

本篇博客接"微服务架构入门"~

我们已经将聚合结构创建好了,一个父级工程三个子集工程,创建好后,我们来看一下父级工程中的pom文件悄悄的发生了什么变化

在这里插入图片描述

在没有创建子集工程前,这一部分是没有的,通过这个图片可以得出结论,父级默认打包方式为pom文件,每构建一个子工程,自动会在modules标签下生成该子工程.

业务描述

我们已经将父子工程创建完毕,接下来我们将sca-qty-provider以及sca-qty-consumer两个子工程注册到Nacos注册中心,实现服务提供者可以为服务消费者提供远程调用.

生产者服务创建及注册

1.配置pom文件

    <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>
    </dependencies>

2.创建并配置application.yml文件

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

注意:name的属性不要用"_"连接,同时注意缩进问题

3.创建启动类

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

4.启动启动类查看Nacos管理界面是否有相应的服务被注册
在这里插入图片描述

如果显示以上图片效果,服务恭喜注册成功

停掉该服务并尝试刷新Nacos页面

大概过了15秒左右的样子,Nacos检测到该服务已经不正常了~
在这里插入图片描述

在第30秒左右的样子,该服务消失了~
在这里插入图片描述

服务检测机制:

每5秒进行检测,俗称检测"心跳"停掉服务15秒,检测时,“心跳"还不跳,标明该服务即将挂掉,在第三十秒,还没有"心跳”,则该服务停止.

消费者服务创建及注册

1.配置pom文件

    <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>
    </dependencies>

2.创建并配置application.yml文件

server:
  port: 8090
spring:
  application:
    name: sca-qty-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

3.在服务提供工程下创建controller包,创建服务提供方独享,基于此对象向外提供服务

@RestController
public class ProviderController {
    @Value("${server.port:8080}")
    private String serverPort;

    @GetMapping("/provider/echo/{msg}")
    public String doRestEcho1(@PathVariable String msg){
        return String.format("%s hello %s", serverPort, msg);
    }
}

4.创建消费者启动类

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

5.在启动类中创建RestTemplate对象,此对象用于远程服务调用

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

此对象可以创建在启动类中,也可以创建在配置类中,因为启动类中包含了配置类注解@Configuration.

6.创建consumer的controller对象,基于此类中的方法,进行远端服务调用

@RestController
@RequestMapping("/consumer")
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;
    @Value("${server.port:8080}")
    private String serverPort;

    @GetMapping("/doRestEcho1")
    public String doRestEcho1(){
        String url = "http://localhost:8081/provider/echo/{msg}";
        return restTemplate.getForObject(url, String.class,serverPort);

    }
}

服务负载均衡设计以及实践

在实际应用场景中,几乎都是多个服务实例并发的状态,这时,我们就需要考虑,服务的负载均衡策略,比如轮询,随机,哈希,权重等策略,LoadBalancerClient对象可以从nacos中基于服务名获取服务实例,然后根据算法实现负载均衡方式的调用.

修改ConsumerController

 @Autowired
    private LoadBalancerClient loadBalancerClient;
    
    @GetMapping("/doRestEcho2")
    public String doRestEcho2(){
        ServiceInstance serviceInstance = 
                loadBalancerClient.choose("sca-qty-provider");
        int port = serviceInstance.getPort();
        String id = serviceInstance.getHost();
        String url = "http://%s:%s/provider/echo/{msg}";
        url = String.format(url,id,port);
        return restTemplate.getForObject(url, String.class,serverPort);

    }

根据LoadBalancerClient对象可以获取到服务列表中的服务名,通过服务名可以获取该服务的id以及port,这样就额能动态并且,多服务并发调用了.可以修改provider的端口,同时启动多个服务,进行调用.

为了测试方便,可以这样做,在resources目录下创建http目录,在http目录下创建consumer-api.http文件

GET http://localhost:8090/consumer/doRestEcho2

测试后发现可以访问多个服务了

@LoadBalanced

假如在调用服务时,需要负载均衡,可以创建LoadBalanced对象来实现,修改Consumer启动类

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

修改controller类

    @Autowired
    private RestTemplate loadBalancedRestTemplate;
    @GetMapping("/doRestEcho3")
    public String doRestEcho3(){
        String url = "http://sca-qty-provider/provider/echo/{msg}";
        return loadBalancedRestTemplate.getForObject(url, String.class, serverPort);
    }

修改http测试文件

GET http://localhost:8090/consumer/doRestEcho2
###
GET http://localhost:8090/consumer/doRestEcho

注意两个请求之间要用"###"隔开,否则,会被而那位是同一个请求路径

上述其实都是基于ReastTemplate对象完成远程服务调用的,LoadBalancerClient可以获取服务列表中的服务名,这样就可以动态获取端口号以及ip,其中@LoadBalanced可以将多个服务访问进行负载均衡

接下来我们再来学习一种远程调用方法—Feign

基于Feign的远程服务调用

为什么会出现Feign

上述远程服务调用都是基于RestTemlate方法,这种方法,一般都是自己拼接url,一不小心就会出现错误,每次调用都会进行拼接,不宜维护,此时Feign出现了

Feign是什么

Feign是一种声明式的web服务客户端,底层封装了rest,通过Feign可以简化服务调用服务的操作,如图所示
在这里插入图片描述

Feign的使用

1.配置消费方的pom文件

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

Feign是由Netfilx开发的,但是后来不进行维护了,现在由SpringCloud进行维护,叫做openFeign

2.在启动类中添加注解@EnableFeignClients

package com.qty;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
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;

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

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

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

@EnableFeignClients:用于扫描配置类或启动类,启动类启动,就会创建一个FeignStart,为注解@Feign的类生成Feign对象.

3.在consumer的controller类中创建一个类


@RestController
@RequestMapping("/consumer")
public class FeignConsumerController {
}

4.创建一个service包,在包下创建一个接口

import org.springframework.cloud.openfeign.FeignClient;

@FeignClient(name = "sca-qty-provider")
public interface RemoteProviderService {
}

在接口中添加注解@FeignClient(name=“服务名”),加了这个注解汇报扫描到,底层就会通过动态代理生成一个实例对象,所以这也就是只声明接口不创建实现类的原因.

5.修改

@RestController
@RequestMapping("/consumer")
public class FeignConsumerController {

    @Autowired
    private RemoteProviderService remoteProviderService;

    @GetMapping("/doFeignEcho/{msg}")
    public String doFeignEcho(@PathVariable String msg){
        return remoteProviderService.echoMessage(msg);
    }
}
@FeignClient(name = "sca-qty-provider")
public interface RemoteProviderService {

    @GetMapping("/provider/echo/{msg}")
    String echoMessage(@PathVariable("msg") String msg);
}

假如同时由多个消费方调用同一个服务提供方,这时就会报错,继续优化

@FeignClient(name = "sca-qty-provider", contextId = "remoteProviderService")
public interface RemoteProviderService {

    @GetMapping("/provider/echo/{msg}")
    String echoMessage(@PathVariable("msg") String msg);
}

我们通过给这个添加一个专属的名字就可以了,但是假如出现500,404等错误,现在会直接让用户看到,很不友好,现在我们来继续优化

在service包下创建此类

import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ProviderError implements FallbackFactory<RemoteProviderService> {
    @Override
    public RemoteProviderService create(Throwable throwable) {
        return msg -> {
            // 这里还可以向运维人员发送报警短信,电话等
            log.error("error: {}","provider服务调用失败");
            return "出错啦";
        };
    }
}

修改RemoteProviderService接口

@FeignClient(name = "sca-qty-provider",
            contextId = "remoteProviderService",
            fallbackFactory = ProviderError.class)
public interface RemoteProviderService {

    @GetMapping("/provider/echo/{msg}")
    String echoMessage(@PathVariable("msg") String msg);
}

修改application.yml配置文件

feign:
  hystrix:
    enabled: true

这样即使调用出错,一会很友好的进行提示,而不是直接俄报404,500等,后台也可以根据日志看到报错信息

手动调节负载均衡策略

第一种方法:

    /**
     * 假如默认的负载均衡不满足需求怎么办
     * 创建一个IRule接口实现类对象
     * 创建随机的负载均衡
     * */
    @Bean
    public IRule iRule(){
        return new RoundRobinRule();
    }

这种方法有个弊端,假如,需要调换策略,那么就会改动源码,所以一般使用第二种方法,修改application.yml配置文件

#直接在配置文件中的配置,其优势是,可以将配置提取到配置中心
sca-provider: #基于服务名指定负载均衡策略
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值