首页 > 其他分享 >【Fegin技术专题】「原生态」打开Fegin之RPC技术的开端,你会使用原生态的Fegin吗?(上)

【Fegin技术专题】「原生态」打开Fegin之RPC技术的开端,你会使用原生态的Fegin吗?(上)

时间:2023-08-09 12:33:31浏览次数:38  
标签:Feign 原生态 String Fegin feign RPC new import public

推荐超值课程:点击获取

前提介绍

  • Feign是SpringCloud中服务消费端的调用框架,通常与ribbon,hystrix等组合使用。
  • 由于遗留原因,某些项目中,整个系统并不是SpringCloud项目,甚至不是Spring项目,而使用者关注的重点仅仅是简化http调用代码的编写。
  • *如果采用httpclient或者okhttp这样相对较重的框架,对初学者来说编码量与学习曲线都会是一个挑战,而使用spring中RestTemplate,又没有配置化的解决方案,由此想到是否可以脱离Spring cloud,独立使用Feign。

内容简介

Feign使得 Java HTTP 客户端编写更方便。Feign 灵感来源于Retrofit、JAXRS-2.0和WebSocket。Feign最初是为了降低统一绑定Denominator到HTTP API的复杂度,不区分是否支持Restful。Feign旨在通过最少的资源和代码来实现和HTTP API的连接。通过可定制的解码器和错误处理,可以编写任意的HTTP API。

maven依赖

  <dependency>
            <groupId>com.netflix.feigngroupId>
            <artifactId>feign-coreartifactId>
            <version>8.18.0version>
        dependency>
        <dependency>
            <groupId>com.netflix.feigngroupId>
            <artifactId>feign-jacksonartifactId>
            <version>8.18.0version>
        dependency>
        <dependency>
            <groupId>io.github.lukehutchgroupId>
            <artifactId>fast-classpath-scannerartifactId>
            <version>2.18.1version>
	   dependency>
	   <dependency>
    	<groupId>com.netflix.feigngroupId>
    	<artifactId>feign-jacksonartifactId>
        <version>8.18.0version>
    dependency>
复制代码

定义配置类

RemoteService service = Feign.builder()
            .options(new Options(1000, 3500))
            .retryer(new Retryer.Default(5000, 5000, 3))
			.encoder(new JacksonEncoder())
            .decoder(new JacksonDecoder())
            .target(RemoteService.class, "http://127.0.0.1:8085");
复制代码
  • options方法指定连接超时时长及响应超时时长
  • retryer方法指定重试策略
  • target方法绑定接口与服务端地址。
  • 返回类型为绑定的接口类型。

自定义接口

随机定义一个远程调用的服务接口,并且声明相关的接口参数和请求地址。

通过@RequestLine指定HTTP协议及URL地址


public class User{
   String userName;
}

public interface RemoteService {

    User getOwner(User user);

    public User getOwner( User user,
         String requestToken,
         Long userId,
         String userName);
}
复制代码

服务提供者

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

public class UserController {

    public User list( User user) throws InterruptedException{
        System.out.println(user.getUsername());
        user.setId(100L);
        user.setUsername(user.getUsername().toUpperCase());
        return user;
    }
}
复制代码

调用

与调用本地方法相同的方式调用feign包装的接口,直接获取远程服务提供的返回值。

String result = service.getOwner(new User("scott"));
复制代码

原生Feign的两个问题

  1. 原生Feign只能一次解析一个接口,生成对应的请求代理对象,如果一个包里有多个调用接口就要多次解析非常麻烦。
  2. Feign生成的调用代理只是一个普通对象,该如何注册到Spring中,以便于我们可以使用@Autowired随时注入。

解决方案:

  1. 针对多次解析的问题,可以通过指定扫描包路径,然后对包中的类依次解析。
  2. 实现BeanFactoryPostProcessor接口,扩展Spring容器功能。

定义一个注解类

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public  FeignApi {

String serviceUrl();
}
复制代码

生成Feign代理并注册到Spring实现类:

import feign.Feign;
import feign.Request;
import feign.Retryer;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner;
import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
import java.util.List;

public class FeignClientRegister implements BeanFactoryPostProcessor{

    private String  scanPath="com.xxx.api";

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        List classes = scan(scanPath);
        if(classes==null){
            return ;
        }
        System.out.println(classes);
        Feign.Builder builder = getFeignBuilder();
        if(classes.size()>0){
            for (String claz : classes) {
                Class targetClass = null;
                try {
                    targetClass = Class.forName(claz);
                    String url=targetClass.getAnnotation(FeignApi.class).serviceUrl();
                    if(url.indexOf("http://")!=0){
                        url="http://"+url;
                    }
                    Object target = builder.target(targetClass, url);
                    beanFactory.registerSingleton(targetClass.getName(), target);
                } catch (Exception e) {
                    throw new RuntimeException(e.getMessage());
                }
            }
        }
    }

    public Feign.Builder getFeignBuilder(){
        Feign.Builder builder = Feign.builder()
                .encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder())
                .options(new Request.Options(1000, 3500))
                .retryer(new Retryer.Default(5000, 5000, 3));
        return builder;
    }

    public List scan(String path){
        ScanResult result = new FastClasspathScanner(path).matchClassesWithAnnotation(FeignApi.class, (Class aClass) -> {
        }).scan();
        if(result!=null){
            return result.getNamesOfAllInterfaceClasses();
        }
        return  null;
    }
}
复制代码
调用接口编写示例:
import com.xiaokong.core.base.Result;
import com.xiaokong.domain.DO.DeptRoom;
import feign.Headers;
import feign.Param;
import feign.RequestLine;
import com.xiaokong.register.FeignApi;

import java.util.List;

public interface RoomApi {

    Result selectById( String id);

    Result> selectList();
}
复制代码
接口使用示例:

public class ServiceImpl{

    private RoomApi roomApi;

    public void demo(){
        Result result = roomApi.selectById("1");
        System.out.println(result);
    }
}
复制代码

注意事项:

  1. 如果接口返回的是一个复杂的嵌套对象,那么一定要明确的指定泛型,因为Feign在解析复杂对象的时候,需要通过反射获取接口返回对象内部的泛型类型才能正确使用Jackson解析。如果不明确的指明类型,Jackson会将json对象转换成一个LinkedHashMap类型。
  2. 如果你使用的是的Spring,又需要通过http调用别人的接口,都可以使用这个工具来简化调用与解析的操作。

分享资源

资源分享
扫码关注发送:资源 获取以上资源
字节技术

标签:Feign,原生态,String,Fegin,feign,RPC,new,import,public
From: https://www.cnblogs.com/3shu/p/17616553.html

相关文章

  • 【Fegin技术专题】「原生态」打开Fegin之RPC技术的开端,你会使用原生态的Fegin吗?(中)
    推荐超值课程:点击获取你可以使用Jersey和CXF这些来写一个Rest或SOAP服务的java客服端。你也可以直接使用ApacheHttpClient来实现。但是Feign的目的是尽量的减少资源和代码来实现和HTTPAPI的连接。*通过自定义的编码解码器以及错误处理,你可以编写任何基于......
  • gRPC Test
    目录简单使用ghzgithub:https://github.com/bojand/ghzghz官方文档:https://ghz.sh/简单使用下载后解压,将目录配置到path上,方便命令调用:ghz--insecure--protoxxx\Hello.proto--callpackage_name.service_name.rpc_method_name-d"{\"name\":\"a\"}"localho......
  • 如何通过gRPC传输文件
    在gRPC中,可以通过将文件分割成多个小块,然后使用流式RPC将这些小块发送到服务器来传输文件。以下是一个简单的示例,展示了如何在gRPC中实现文件传输。首先,我们需要定义一个服务来处理文件传输。在.proto文件中,我们可以定义一个UploadFile服务,它接收一个流式的Chunk消息,并返回一个Up......
  • gRPC的测试
    gRPC(Googleremoteprocedurecall)远程过程调用,使不同服务在不同机器上互相调用就像调本地一样方便但调用方和服务方对应开发不是一个人,出现问题,没法确认是哪方的问题,因此,可以使用BloomRPC工具测试rpc服务是否正常 1、测试工具:BloomRPC,下载地址 https://github.com/uw-labs/......
  • Python中实现远程调用(RPC、RMI)简单例子
    远程调用使得调用远程服务器的对象、方法的方式就和调用本地对象、方法的方式差不多,因为我们通过网络编程把这些都隐藏起来了。远程调用是分布式系统的基础。远程调用一般分为两种,远程过程调用(RPC)和远程方法调用(RMI)。RPCRPC属于函数级别的远程调用,其多是通过HTTP传输数据,数据形式有......
  • docker 中使用 pywpsrpc
    一般如果使用带桌面环境的docker,比如dorowu/ubuntu-desktop-lxde-vnc,然后安装wps后,使用https://github.com/timxx/pywpsrpc是没啥问题的,需要注意的是wps第一次打开后,需要同意EULA,然后按照https://github.com/timxx/pywpsrpc/issues/44#issuecomment-1032304847中提到的......
  • CENTOS7下安装GRPC FOR CPP
    gRPC是一个高性能、开源和通用的RPC框架,面向移动和HTTP/2设计。目前提供C、Java和Go语言版本,分别是:grpc,grpc-java,grpc-go.其中C版本支持C,C++,Node.js,Python,Ruby,Objective-C,PHP和C#。gRPC基于HTTP/2标准设计,带来诸如双向流、流控、头部压缩、单TC......
  • Golang gRPC学习(05): retry重试
    什么是重试如果服务出现了错误,主要是网络,服务器出现了短暂异常的时候,该怎么办?我们都会人工或者自动的重新连接服务试试,看服务是否恢复可用了。这种重新进行连接服务的一种方式就是重试。如果是在微服务里,应该属于微服务治理的范畴。重试是处理网络服务出现暂时不可用的一种方......
  • API架构的选择,RESTful、GraphQL还是gRPC
    API架构的选择,RESTful、GraphQL还是gRPC hi,我是熵减,见字如面。在现代的软件工程中,微服务或在客户端与服务端之间的信息传递的方式,比较常见的有三种架构设计的风格:RESTful、GraphQL和gRPC。每一种模式,都有其特点和合适的使用场景,今天,我们主要来对三种风格做一个深入的理解......
  • .NET 7 使用gRpc
    Server端 添加proto文件,编辑项目文件添加proto文件,编译项目 添加Service服务 启动Server Client端安装package Copy proto文件到项目里   ......