05Feign的解码器处理响应数据解码器就是⽤于Response
1 Decoder
public interface Decoder {
// response:代表请求响应
// type:代表⽅法的返回值类型
// 它还有个特点:抛出了三种异常
// 但其实除了IOException,其它两种都是unchecked异常
Object decode(Response response, Type type)throws IOException, DecodeException, FeignException;unknown怎么处理
}
将Http响应sponse解码为指定的单⼀对象,触发前提:
响应码是2xx
⽅法返回值不是null或者void,也不是sponse。
1.1 实现⼀:StreamDecoder
⽀持的返回值类型是Java的java.util.stream.Stream类型的返回值
public final class StreamDecoder implements Decoder {
/**
内部还依赖⼀个Decoder,可迭代的解码器
**/
private final Decoder iteratorDecoder;
StreamDecoder(Decoder iteratorDecoder){
this.iteratorDecoder = iteratorDecoder;
}
@Override
public Object decode(Response response, Type type)
throws IOException, FeignException {
// 不是参数化类型类型就会抛出异常
if(!(type instanceof ParameterizedType)){
throw new IllegalArgumentException("StreamDecoder supports only stream: unknown "+ type); }
ParameterizedType streamType =(ParameterizedType) type;
// 不是Stream类型也会抛出错,可见这个解码器只⽀持是feign接⼝返回值是,Stream类型
// getRawType:返回最外层<>前⾯那个类型,即Map<K ,V>的Map。
if(!Stream.class.RawType())){
throw new IllegalArgumentException("StreamDecoder supports only stream: unknown "+ type); }
/
/ 这个可迭代的解码器返回值就是⼀个迭代器
Iterator<?> iterator =
(Iterator) iteratorDecoder.decode(response,new IteratorParameterizedType(streamType)); // 将可迭代的解码器返回的迭代器转换为stream流
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(iterator,0),false)
.onClose(()->{
if(iterator instanceof Closeable){
ensureClosed((Closeable) iterator);
}else{
ensureClosed(response);
}
});
}
/**
提供了⼀个静态⽅法创建⾃⼰的实例
**/
public static StreamDecoder create(Decoder iteratorDecoder){
return new StreamDecoder(iteratorDecoder);
}
...
}
要点:
内部依赖了⼀个迭代的解码器,该解码器返回值就是⼀个可迭代的对象
提供了静态⽅法创建⾃⼰的实例
这个解码器只⽀持是feign接⼝返回值是,Stream类型、
** 最后将可迭代的解码器返回的迭代器转换为stream流返回**
实际开发中⽤的很少,⼀般不会把流作为接⼝的返回值的
1.1.1 demo
1. 服务提供者:
@RestController
@RequestMapping("/feign/provider")
public class StreamDecoderController {
@GetMapping("streamDecoder/test01")
public List<String>test01(){
return Arrays.asList("java","python","javaScript");
}
}
2. feign客户端
@RequestLine("GET /feign/provider/streamDecoder/test01")
Stream<String>test01();
3. 测试
public class StreamDecoderClientTest {
public static String HOST ="localhost:8001";
public StreamDecoderClient build(){
return Feign.builder()
// 输出⽇志到控制台
.logger(new Logger.ErrorLogger()).logLevel(Logger.Level.FULL)
// 关闭重试
.retryer(Retryer.NEVER_RETRY)
// 404进⾏编码,404的时候就不会抛出异常了
.decode404()
// 注册StreamDecoder解码器,主要需要提供⼀个iteratorDecoder
.ate((response,type)->{
// 获取响应,rest风格返回值是个json字符串
Response.Body body = response.body();
/
/ 解析出来的字符传数据就是json格式的字符串:["java","python","javaScript"] String json = String(body.asReader());
// 就简单处理,使⽤,号分割
// 返回⼀个迭代器
return Arrays.stream(json.split(",")).iterator();
}))
.target(StreamDecoderClient.class,HOST);
}
@Test
public void test01(){
StreamDecoderClient client =build();
Stream<String> stream = st01();
stream.forEach(System.out::println);
}
}
测试输出:
[StreamDecoderClient#test01]---> GET localhost:8001/feign/provider/streamDecoder/test01 HTTP/1.1 [StreamDecoderClient#test01]---> END HTTP (0-byte body)
[StreamDecoderClient#test01]<--- HTTP/1.1200(44ms)
[StreamDecoderClient#test01] connection: keep-alive
[StreamDecoderClient#test01] content-type: application/json
[StreamDecoderClient#test01] date: Tue,23 Mar 202101:09:26 GMT
[StreamDecoderClient#test01] keep-alive: timeout=60
[StreamDecoderClient#test01] transfer-encoding: chunked
[StreamDecoderClient#test01]
[StreamDecoderClient#test01]["java","python","javaScript"]
[StreamDecoderClient#test01]<--- END HTTP (30-byte body)
["java"
"python"
"javaScript"]
在streamDecoder的核⼼⽅法decode⽅法都打个断点,观察⼀下具体的参数:
1.2 实现⼆:OptionalDecoder
⽀持java8Optionall类型
// 内部依旧持有⼀个解码器,该解码器的返回值就得是⼀个Optional类型
final Decoder delegate;
public OptionalDecoder(Decoder delegate){
this.delegate = delegate;
}
@Override
public Object decode(Response response, Type type)throws IOException {
// 如果feign接⼝的返回值不是Optional类型
if(!isOptional(type)){
// 那就返回持有的解码器返回的结果
return delegate.decode(response, type);
}
if(response.status()==404|| response.status()==204){
pty();
}
Type enclosedType = solveLastTypeParameter(type, Optional.class);
// 如果接⼝的返回值是Optional,就会把持有的解码器的数据⽤Optional包装起来
return Optional.ofNullable(delegate.decode(response, enclosedType));
}
要点:
内部持有⼀个解码器,需要⾃⼰实现,该解码器的返回值会被OptionalDecoder处理
处理⽅式由两种:
如果接⼝的返回值是Optional类型,最后就会被Optional包装起来
如果接⼝的返回值不是Optional类型,就会直接接返回内部持有解码器返回的结果
1.2.1 demo
1. 服务提供者
@RestController
@RequestMapping("/feign/provider")
public class OptionalDecoderController {
@GetMapping("optionalDecoder/test01")
public List<String>test01(){
return Arrays.asList("java","python","javaScript");
}
}
2. feign客户端
public interface OptionalDecoderClient {
/**
* 返回值是Optional类型
* @return
*/
@RequestLine("GET /feign/provider/optionalDecoder/test01") Optional<List<String>>test01();
/**
* 返回值不是Optional类型
* @return
*/
@RequestLine("GET /feign/provider/optionalDecoder/test01") List<String>test02();
}
3. 测试
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论