day03 ---远程服务调用Feign

1.远程服务调用Feign

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

1.1 什么是Feign?

Feign 是一种声明式Web服务客户端,底层封装了对Restemplate技术的应用,通过Feign可以简化服务消费方对远程服务提供方法的调用实现。Feign 最早是由 Netflix 公司进行维护的,后来 Netflix 不再对其进行维护,最终 Feign 由社区进行维护,更名为 OpenFeign。
在这里插入图片描述

1.2 Feign实例

1.2.1 添加项目依赖

在服务消费方sca-consumer ,SpringCloud团队基于OpenFeign研发了starter

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

1.2.2 添加@EnableFeignClients注解

在服务消费方sca-consumer 中的启动类上,添加@EnableFeignClients
注解描述启动类时,用于告诉springboot在启动时,扫描启动类所在包或子包中的类,假如接口上有@FeignClient注解描述,则对这样的接口创建其实现类,在实现类内部帮我们进行远程服务调用


import org.springframework.cloud.openfeign.EnableFeignClients;
//@EnableFeignClients注解描述启动类时,用于告诉springboot在启动时,
//扫描启动类所在包或子包中的类,假如接口上有@FeignClient注解描述,则对
//这样的接口创建其实现类,在实现类内部帮我们进行远程服务调用
@EnableFeignClients //
@SpringBootApplication
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);

    }

1.2.3 借助OpenFeign访问远端服务

创建接口RemoteProviderService 作为业务层
@FeignClient 注解用于描述远程服务调用接口,与启动类的@EnableFeignClients,共同为我们创建业务层实现类
@FeignClient(name=“要调用的服务的名”,contextId = “当前bean对象的名字”,fallbackFactory = 访问异常时解决.class)

package com.jt.feign;


import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @FeignClient 注解用于描述远程服务调用接口,这个接口不需要你写实现类,你
 * 只需要定义访问规则即可(例如请求方式,请求url,请求参数).
 * @FeignClient注解描述的接口的实现类对象会默认交给spring管理,这个bean对象
 * 的名字默认就是name属性指定的值,这个name还有一个层面的含义,就是你远程调用的
 * 服务名.
 * 说明:假如@FeignClient注解中添加contextId属性,则这个属性值默认
 * 会作为当前bean对象的名字,此时name的值仅仅作为要调用的服务的名对待,一般推荐contextId
 * 的值默认为@FeignClient注解描述的接口的名字(首字母小写)
 * //
 */
@FeignClient(name="sca-provider",
        contextId = "remoteProviderService",fallbackFactory = ProviderFallbackFactory.class)
public interface RemoteProviderService {
    //@GetMapping表示以get请求方式调用远端服务
    //"/provider/echo/{msg}"为远程调用服务的url
    @GetMapping("/provider/echo/{msg}")
    String echoMessage(@PathVariable("msg") String msg);//("msg")指定解析restful方式传递来的参数 msg
}

1.2.4 添加feign访问

创建FeignConsumerController
**注意映射路径不要重复,否则启动失败


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

1.2.5 启动消费者服务测试

访问 http://localhost:8090/test/echo/8090
在这里插入图片描述

1.3 Feign配置进阶

1.3.1 Feign没有指定contextId问题

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

添加 interface RemoteOtherService ,把@FeignClient中的contextId设置为无参,多个服务访问接口请求同名sca-provider

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

在这里插入图片描述

1.3.2 Feign调用过程超时

在ProviderController中添加 睡眠10s,模仿超时情况
在这里插入图片描述
解决办法:
1.定义FallbackFactory接口的实现,此对象可以作为Feign方式的远程调用异常处理对象

package com.jt.feign;

import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;


@Component
public class ProviderFallbackFactory implements FallbackFactory<RemoteProviderService> {
    //此对象可以作为Feign方式的远程调用异常处理对象
    @Override
    public RemoteProviderService create(Throwable throwable) {
/*        return new RemoteProviderService() {//匿名内部类
            @Override
            public String echoMessage(String msg) {
                //通知运维人员(发短信)
                return "服务维护中";
            }*/
        return (msg)->{//拉姆达表达式
            return "服务维护中,稍等片刻再访问";
        };
    }
}

2.在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);
}

3.在application.yml中添加服务中断处理机制

#feign方式的服务熔断处理
feign:
  hystrix:  #hystrix  含义就是熔断(就相当于服务终止了)或降级
    enabled: true 	#默认值为false

测试结果:
在这里插入图片描述

1.4 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 返回客户端,将信息流解析成为接口返回数据。
在这里插入图片描述

1.5面试分析

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

1.6 tomcat----socket知识点补充

package com.jt.net;

import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Tomcat {
    public static void main(String[] args) throws IOException {

        //Java中服务的创建
        System.out.println("start server ...");
        //Java中网络编程中的服务对象类型为ServerSocket
        //构建服务,并在9999端口进行监听
        ServerSocket server=new ServerSocket(9999);
        //等待服务端的连接
        while(true){
            //这里的socket代表客户端对象
            Socket socket=server.accept();//阻塞式方法
            System.out.println("hello client "+socket);
            //获取向客户端输出数据的流对象
            OutputStream out=socket.getOutputStream();
            //向客户端写数据
            //out.write("hello".getBytes());//这种方式浏览器不会显示
            String content="HTTP/1.1 200\r\n" +//响应行
                    "Content-Type: text/html;charset=UTF-8\r\n"+//响应头
                    "\r\n"+//空行,
                    "<h1>hello client</h1>"; //数据
            out.write(content.getBytes());
            socket.close();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值