Feign 自定义编码器、解码器和客户端

时间:2022-10-06 19:01:46

Feign 的编码器、解码器和客户端都是支持自定义扩展,可以对请求以及结果和发起请求的过程进行自定义实现,Feign 默认支持 JSON 格式的编码器和解码器,如果希望支持其他的或者自定义格式就需要编写自己的编码器和解码器,如果希望编写自己的编码器,需要实现 feign.codec.Encoder 接口,解码器需要实现 feign.codec.Decoder 接口,示例如下:

自定义编码器和解码器

  • 自定义编码器

    实现的自定义编码器只是输出了需要编码的参数信息,而具体的编码还是使用 JSON 格式,使用了 GsonEncoder 编码器来完成具体的编码工作,参数 object 表示需要进行编码的对象,参数 bodyType 为 object 对象的类型,参数 template 表示的就是请求模板,该方法就是需要实现将参数 object 进行编码并赋值到 template 请求模板中。

    package org.lixue.feignclient;

    import feign.RequestTemplate;

    import feign.codec.EncodeException;

    import feign.codec.Encoder;

    import feign.gson.GsonEncoder;

    import java.lang.reflect.Type;

    public class MyEncoder implements Encoder{

    private GsonEncoder gsonEncoder;

    publicMyEncoder(){

    gsonEncoder = new GsonEncoder();

    }

    public void encode(Object object,Type bodyType,RequestTemplate template) throws EncodeException{

    System.out.println("encode object is class"+object.getClass().getName());

    System.out.println("encode object is value"+object);

    System.out.println("encode bodyType is class"+bodyType.getClass().getName());

    System.out.println("encode bodyType is value"+bodyType);

    gsonEncoder.encode(object,bodyType,template);

    }

    }

  • 自定义解码器

    实现的自定义解码器使用了 GsonDecoder 解码器来完成具体的编码工作,解码器相对简单,只需要从响应中获取响应报文,然后按照指定的编码格式相应的解码并创建指定的类型实例即可。

    package org.lixue.feignclient;

    import feign.FeignException;

    import feign.Response;

    import feign.codec.DecodeException;

    import feign.codec.Decoder;

    import feign.gson.GsonDecoder;

    import java.io.IOException;

    import java.lang.reflect.Method;

    import java.lang.reflect.Type;

    public class MyDecoder implements Decoder{

    private GsonDecoder gsonDecoder;

    publicMyDecoder(){

    gsonDecoder=newGsonDecoder();

    }

    public Object decode(Response response,Type type)throws IOException,DecodeException,FeignException{

    return gsonDecoder.decode(response,type);

    }

    }

  • 测试验证

    在完成自定义编码器和解码器的开发后,只需要在 Feign 的 builder 方法中,增加解码器和编码器即可,需要注意的是,如果方法请求参数或返回的不是对象,不需要进行编码或解码,就不能增加编码器或解码器,示例代码如下:

    package org.lixue.feignclient;

    import feign.Feign;

    import feign.Logger;

    import feign.gson.GsonDecoder;

    import feign.gson.GsonEncoder;

    public class Startup{

    public static void main(String[]args){

    HelloWorldClient speakClient=

    Feign.builder().target(HelloWorldClient.class,"http://localhost:8080/");

    // 参数和返回都不是对象,不需要附加编码器和解码器

    System.out.println(speakClient.speak("isbody"));

    HelloWorldClient findByIdClient=

    Feign.builder().decoder(new GsonDecoder())

    .target(HelloWorldClient.class,"http://localhost:8080/");

    // 返回的是对象,需要附加解码器

    Person person=findByIdClient.findById(34);

    System.out.println("personid="+person.getId()+"age="+person.getAge()+"name="+person.getName()+"message="+person.getMessage());

    HelloWorldClient createClient=

    Feign.builder().client(newMyClient())

    .decoder(newMyDecoder())

    .encoder(newMyEncoder())

    .target(HelloWorldClient.class,"http://localhost:8080/");

    Person newPerson=new Person();

    newPerson.setId(3434);

    newPerson.setAge(34);

    newPerson.setName("343434");

    newPerson.setMessage("33333333333333333");

    // 参数和返回都是对象,需要附加解码器和编码器

    ReturnValuereturnValue=createClient.create(newPerson);

    System.out.println(returnValue.parseString());

    }

    }

自定义 Feign 客户端

  • 自定义 Feign 客户端

    Feign 使用一个 feign.Client 接口来发送请求,默认实现是使用 HttpURLConnection 连接 HTTP 服务,我们可以实现 feign.Client 接口来完成自定义 Feign 客户端的开发,该接口只有一个方法 execute ,用于执行请求,下面实现了一个自定义的 Feign 客户端,主要完成了请求的日志记录,示例代码如下:

    package org.lixue.feignclient;

    import feign.Client;

    import feign.Request;

    import feign.Response;

    import java.io.IOException;

    import java.util.Collection;

    import java.util.Map;

    public class MyClient implements Client{

    public Response execute(Request request,Request.Options options)throws IOException{

    System.out.println("execute request method="+request.method());

    System.out.println("execute request headers");

    Map<String,Collection<String>> headers=request.headers();

    for(Map.Entry<String,Collection<String>> entry:headers.entrySet()){

    StringBuilderstringBuilder=newStringBuilder();

    for(intj=0;j<entry.getValue().size();j++){

    if(stringBuilder.length()>0){

    stringBuilder.append(",");

    }

    stringBuilder.append(entry.getValue());

    }

    System.out.println(entry.getKey()+":"+stringBuilder.toString());

    }

    byte[] body=request.body();

    if(body!=null){

    System.out.println("execute request body="+newString(body));

    }

    // 使用 Feign 默认的客户端请求

    return new Client.Default(null,null).execute(request,options);

    }

    }

  • 测试验证

    和附加编码器、解码器类似,只需要在 Feign 的 builder 方法中附加自定义的客户端即可,代码如下:

    package org.lixue.feignclient;

    import feign.Feign;

    import feign.Logger;

    import feign.gson.GsonDecoder;

    import feign.gson.GsonEncoder;

    public class Startup{

    public static void main(String[]args){

    HelloWorldClient findByIdClient=

    Feign.builder().client(new MyClient())

    .decoder(new GsonDecoder())

    .target(HelloWorldClient.class,"http://localhost:8080/");

    Person person=findByIdClient.findById(34);

    System.out.println("personid="+person.getId()+"age="+person.getAge()+"name="+person.getName()+"message="+person.getMessage());

    }

    }