微服务架构-03

本文详细介绍了Feign的使用,包括客户端和服务端交互的基础知识,任务调度的实现,以及Feign在服务调用中的核心作用。Feign作为声明式Web服务客户端,简化了RESTful服务的调用,通过配置可以实现负载均衡和容错处理。文中还通过实例展示了Feign的配置进阶,包括服务接口的唯一标识和异常处理。最后,分析了Feign的调用过程,揭示了其底层逻辑。
摘要由CSDN通过智能技术生成

目录

客户端与服务端交互

客户端

服务端

任务调度

基于Feign的远程服务调用(重点)

背景分析

Feign是什么

Feign应用实践(掌握)

Feign配置进阶实践

整体代码

Feign 调用过程分析(了解)

小节面试分析

总结(Summary)

重难点分析

FAQ分析


客户端与服务端交互

客户端

package com.cy;

import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 * 网络中的客户端对象
 * */

public class Browser {
    public static void main(String[] args) throws IOException {
        //1.构建客户端对象,连接服务端
        Socket socket = new Socket("127.0.0.1",8848);
        //2.与服务端进行交互
        ObjectOutputStream out =
                new ObjectOutputStream(socket.getOutputStream());
        out.writeUTF("Browser");
        //3.释放资源
        out.close();
        socket.close();
    }
}

服务端

public class Tomcat {

    static boolean flag =true;
    public static void main(String[] args) throws IOException {
        //1.创建一个服务对象,并在8848端口进行监听
        ServerSocket serverSocket = new ServerSocket(8848);
        System.out.println("server start...");

        //2.开启服务监听(等待客户端的链接)
        while(flag){
            //2.1接收客户端的请求
            Socket socket = serverSocket.accept();//接收请求(没有请求时Thread.sleep(..);)
            System.out.println("socket:"+socket);

            //2.2处理客户端的请求
            ObjectInputStream ois =
                    new ObjectInputStream(socket.getInputStream());//可以读取对象
            String msg = ois.readUTF();
            System.out.println("client say:"+msg);


        }
    }

}

任务调度

package com.cy;

import java.util.Timer;
import java.util.TimerTask;

/**
 * 任务调度:单线程的时候使用
 * */
public class TimerTests {
    public static void main(String[] args) {
        //构建一个timer对象负责执行任务调度
        Timer timer = new Timer();
        //执行任务调度(TimerTask表示表示任务类型)
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(System.currentTimeMillis());
            }
        }, 5000,//1秒以后开始执行
                5000);//每隔1s执行一次
    }
}

基于Feign的远程服务调用(重点)



背景分析

服务消费方基于rest方式请求服务提供方的服务时,一种直接的方式就是自己拼接url,拼接参数然后实现服务调用,但每次服务调用都需要这样拼接,代码量复杂且不易维护,此时Feign诞生。

Feign是什么

Feign 是一种声明式Web服务客户端,底层封装了对Rest技术的应用,通过Feign可以简化服务消费方对远程服务提供方法的调用实现。如图所示:

 Feign 最早是由 Netflix 公司进行维护的,后来 Netflix 不再对其进行维护,最终 Feign 由一些社区进行维护,更名为 OpenFeign。

Feign应用实践(掌握)

第一步:在服务消费方,添加项目依赖(SpringCloud团队基于OpenFeign研发了starter),代码如下:

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

第二步:在启动类上添加@EnableFeignClients注解,代码如下:

@EnableFeignClients
@SpringBootApplication
public class ConsumerApplication {…}

第三步:定义Http请求API,基于此API借助OpenFeign访问远端服务,代码如下:

@FeignClient(name="sca-provider")//sca-provider为服务提供者名称
interface RemoteProviderService{
    @GetMapping("/provider/echo/{string}")//前提是远端需要有这个服务
    public String echoMessage(@PathVariable("string") String string);
}

其中,@FeignClient描述的接口底层会为其创建实现类。

第四步:创建FeignConsumerController中并添加feign访问,代码如下:


@RestController
@RequestMapping("/consumer/ ")
public class FeignConsumerController {
    @Autowired
    private RemoteProviderService remoteProviderService;
    /**基于feign方式的服务调用*/
    @GetMapping("/echo/{msg}")
    public String doFeignEcho(@PathVariable  String msg){
        //基于feign方式进行远端服务调用(前提是服务必须存在)
        return remoteProviderService.echoMessage(msg);
    }
}

第五步:启动消费者服务,在浏览器中直接通过feign客户端进行访问,如图所示(反复刷新检测其响应结果):

在这里插入图片描述

Feign配置进阶实践

一个服务提供方通常会提供很多资源服务,服务消费方基于同一个服务提供方写了很多服务调用接口,此时假如没有指定contextId,服务
启动就会失败,例如假如在服务消费方再添加一个如下接口,消费方启动时就会启动失败,例如:


 @FeignClient(name="sca-provider")
 public interface RemoteOtherService {
     @GetMapping("/doSomeThing")
     public String doSomeThing();
}

其启动异常:

The bean 'optimization-user.FeignClientSpecification', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.

此时我们需要为远程调用服务接口指定一个contextId,作为远程调用服务的唯一标识即可,例如:

@FeignClient(name="sca-provider",contextId="remoteProviderService")//sca-provider为服务提供者名称
interface RemoteProviderService{
    @GetMapping("/provider/echo/{string}")//前提是远端需要有这个服务
    public String echoMessage(@PathVariable("string") String string);
}

还有,当我们在进行远程服务调用时,假如调用的服务突然不可用了或者调用过程超时了,怎么办呢?一般服务消费端会给出具体的容错方案,例如:
第一步:定义FallbackFactory接口的实现,代码如下:

package com.cy.service.factory;
/**
 * 基于此对象处理RemoteProviderService接口调用时出现的服务中断,超时等问题
 */
@Component
public class ProviderFallbackFactory
        implements FallbackFactory<RemoteProviderService> {
    /**
     * 此方法会在RemoteProviderService接口服务调用时,出现了异常后执行.
     * @param throwable 用于接收异常
     */
    @Override
    public RemoteProviderService create(Throwable throwable) {
        return (msg)->{
                return "服务维护中,稍等片刻再访问";
        };
    }
}

第二步:在Feign访问接口中应用FallbackFactory对象,例如:

@FeignClient(name = "sca-provider", contextId = "remoteProviderService",
             fallbackFactory = ProviderFallbackFactory.class)//sca-provider为nacos中的服务名
public interface RemoteProviderService {
    @GetMapping("/provider/echo/{msg}")
    public String echoMsg(@PathVariable String msg);
}

第三步:在配置文件application.yml中添加如下配置,启动feign方式调用时的服务中断处理机制.

feign:  
  hystrix:
    enabled: true #默认值为false

第四步:在服务提供方对应的方法中添加Thread.sleep(500000)模拟耗时操作,然后启动服务进行访问测试.

整体代码

package com.cy.service;

import com.cy.factory.ProviderFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name="sca-provider-demo1",
        contextId="remoteProviderService",fallbackFactory = ProviderFallbackFactory.class)
public interface RemoteProviderService {
    @GetMapping("/provider/echo/{msg}")
    String echoMessage(@PathVariable("msg") String msg);
}

package com.cy.factory;

import com.cy.service.RemoteProviderService;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;

@Component
public class ProviderFallbackFactory implements FallbackFactory<RemoteProviderService> {

    @Override
    public RemoteProviderService create(Throwable throwable) {
        return (msg)->{
            return "服务维护中";
        };
    }
}

package com.cy.controller;

import com.cy.service.RemoteProviderService;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/consumer")
public class FeignConsumerController {
    @Autowired
    private RemoteProviderService remoteProviderService;

    @GetMapping("/echo/{msg}")
    public String doFeignEcho(@PathVariable String msg){
        return remoteProviderService.echoMessage(msg);
    }
}

package com.cy;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

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

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

        @GetMapping("/provider/echo/{msg}")
        public String doRestEcho1(@PathVariable String msg) throws InterruptedException {
            Thread.sleep(5000);
            return server+"看不见你的笑我怎么睡得着, "+msg;
        }
    }
}

Feign 调用过程分析(了解)

Feign应用过程分析(底层逻辑先了解):
1)通过 @EnableFeignCleints 注解告诉springcloud,启动 Feign Starter 组件。
2) Feign Starter 在项目启动过程中注册全局配置,扫描包下所由@FeignClient注解描述的接口,然后由系统底层创建接口实现类(JDK代理类),并构建类的对象,然后交给spring管理(注册 IOC 容器)。
3) 接口被调用时被动态代理类逻辑拦截,将 @FeignClient 请求信息通过编码器生成 Request对象,基于此对象进行远程过程调用。
4) 请求对象经Ribbon进行负载均衡,挑选出一个健康的 Server 实例(instance)。
5) 通过 Client 携带 Request 调用远端服务返回请求响应。
6) 通过解码器生成 Response 返回客户端,将信息流解析成为接口返回数据。

小节面试分析

  • 为什么使用feign?(基于Feign可以更加友好的实现服务调用,简化服务消费方对服务提供方方法的调用)。
  • @FeignClient注解的作用是什么?(告诉Feign Starter,在项目启动时,为此注解描述的接口创建实现类-代理类)
  • Feign方式的调用,底层负载均衡是如何实现的?(Ribbon)
  • @EnableFeignCleints 注解的作用是什么?(描述配置类,例如启动类)

总结(Summary)



重难点分析

  • 何为注册中心?(用于记录服务信息的一个web服务,例如淘宝平台,滴滴平台,美团外卖平台,……)
  • 注册中心的核心对象?(服务提供方,服务消费方,注册中心-Registry)
  • 市面上常用注册中心?(Google-Consul,Alibaba-Nacos,…)
  • 微服务架构下项目的构建过程?(聚合工程)
  • Nacos安装、启动、服务的注册、发现机制以及实现过程?
  • Feign的基本应用以及底层底层调用原理?

FAQ分析

  • Nacos是什么,提供了什么特性(服务的注册、发现、配置)?
  • 你为什么会选择Nacos?(活跃度、稳定、性能、学习成本)
  • Nacos的官网?(nacos.io)
  • Nacos在github的源码?(github.com/alibaba/nacos)
  • Nacos在windows环境下安装?(解压即可使用)
  • Nacos在windows中的的初步配置?(application.properties访问数据库的数据源)
  • Nacos服务注册的基本过程?(服务启动时发送web请求)
  • Nacos服务消费的基本过程?(服务启动时获取服务实例,然后调用服务)
  • Nacos服务负载均衡逻辑及设计实现?(Ribbon)
  • 注册中心的核心数据是什么?(服务的名字和它对应的网络地址)
  • 注册中心中心核心数据的存取为什么会采用读写锁?(底层安全和性能)
  • Nacos健康检查的方式?(基于心跳包机制进行实现)
  • Nacos是如何保证高可用的?(重试,本地缓存、集群)
  • Feign是什么,它的应用是怎样的,feign应用过程中的代理对象是如何创建的(JDK)?
  • Feign方式的调用过程,其负载均衡是如何实现?(Ribbon)
     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值