Fegin使用——基本方式
@FeignClient(value = "XdocConsumer")
public interface XdocConsumer {
}
/*
传单个文件
*/
@PostMapping(value = "/xdoc/upLoadFile/{employeeId}",produces = {MediaType.APPLICATION_JSON_UTF8_VALUE},
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
ResponseVO upLoadFile(@RequestPart(value = "file", required = false) MultipartFile file,@PathVariable("employeeId")String employeeId);
/*
传body参数
*/
@PostMapping("/xdoc/backStageOper/")
ResponseVO queryOnlySelfInvoice(@RequestBody XdocPo po)
}
GitHub github = Feign.builder()
.decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com");
Fegin使用——定义拦截器
@Configuration
@Slf4j
public class FeignInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
/*
利用Tomcat全局工具类拿出请求参数
并获取所有请求头
*/
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes == null) {
return;
}
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
/*
利用迭代器便利所有头,然后去request,getKey拿到value值
*/
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
Enumeration<String> values = request.getHeaders(name);
while (values.hasMoreElements()) {
String value = values.nextElement();.
/*
对于multipart的特殊处理
*/
if(name.toLowerCase().equals("content-type") && value.contains("multipart/form-data")){
value= "application/json";
}
/*
在模板中一个个value复制过来,复制请求头
*/
template.header(name, value);
}
}
}
}
}
Fegin使用——自定义异常处理器
异常解析器
@Configuration
public class FeginExcpetionDecoder {
/**
* @HttpStatus状态码200-300的时候进入这个处理器进行全局fegin异常处理 通过ErrorDecoder对异常封装成可以识别的异常丢给全局处理器
*/
@Bean
public ErrorDecoder errorDecoder() {
return new ErrorDecoder() {
public Exception decode(String methodKey, Response response) {
if (response.status() == 404) {
return new ApiRemoteNotFoundException("远程调用404,方法名为:" + methodKey);
}
String feginDataJson = null;
Exception exception = null;
try {
feginDataJson = Util.toString(response.body().asReader(Charset.defaultCharset()));
ResponseVO errorResponseVO = JSON.parseObject(feginDataJson, ResponseVO.class);
exception= discernRemoteException(errorResponseVO);
} catch (JSONException e) {
/**
* 如果JSON格式不一致则会抛出这个异常
* 比如:404错误类型由tomcat特殊封装一个VO返回,这个VO的结构如下
* status:……
* error:……
*/
exception = new ApiRemoteParseException(
e.getMessage()+JSON.parseObject(feginDataJson).get("error").toString()
);
} catch (Exception e) {
/**
* 未知异常打印日志信息
*/
exception = new ApiNativeNoneException(e.getMessage());
}
return exception;
}
};
}
public static ApiRemoteBaseException discernRemoteException(ResponseVO responseVO){
if(responseVO.getCode()==404){
return new ApiRemoteNotFoundException(responseVO.getErrorTip());
}else if(responseVO.getCode()>=500&&responseVO.getCode()<10000){
return new ApiRemoteServiceException(responseVO);
}
return new ApiRemoteNoneException(responseVO);
}
}
全局异常处理
@RestControllerAdvice
public class WebGlobalExceptionHandler {
@ResponseBody
@ExceptionHandler(ApiRemoteBaseException.class)
public ResponseVO apiRemoteException(ApiRemoteBaseException ex, HttpServletResponse response) {
response.setStatus(ex.getCode());
ExceptionUtils.errorLogOutput("Api远程调用异常————日志提示信息:"+ex.getMsg());
ExceptionUtils.errorLogOutput("Api远程调用异常————日志提示信息:"+ex.getErrorTip());
return ExceptionUtils.errorApiRmoteExceptionView(ex);
}
@ResponseBody
@ExceptionHandler(ApiNativeNoneException.class)
public ResponseVO apiNoneException(ApiNativeNoneException ex, HttpServletResponse response) {
response.setStatus(ex.getCode());
ExceptionUtils.errorLogOutput("Api未知异常————日志提示信息:"+ex.getMsg());
ExceptionUtils.errorLogOutput("Api未知异常————日志提示信息:"+ex.getErrorTip());
return ExceptionUtils.errorNativeUnknownExcpetionView(ex);
}
@ResponseBody
@ExceptionHandler(Exception.class)
public ResponseVO exception(Exception ex, HttpServletResponse response) {
response.setStatus(500);
ExceptionUtils.errorLogOutput("全局未知异常————日志提示信息:"+ex.getMessage());
return ExceptionUtils.errorNativeUnknownExcpetionView(ex);
}
}
Fegin源码——创建机制
由于fegin是由hytyric创建的,所以我们学完hytric再来讨论这个问题
Fegin源码——调用机制
SynchronousMethodHandler——请求与响应衔接调用层
这一层主要是根据http的状态去决定调用不同的编解码实现类
final class SynchronousMethodHandler implements MethodHandler {
/*
Fegin完成api发送的组件存储
*/
private static final long MAX_RESPONSE_BUFFER_SIZE = 8192L;
private final MethodMetadata metadata;//封装了fegin接口的解析到的方法的核心数据,比如,返回值类型
private final Target<?> target;//目标代理类
private final Client client;//创建网络请求的类
private final Retryer retryer;
private final List<RequestInterceptor> requestInterceptors;
private final RequestTemplate.Factory buildTemplateFromArgs;//请求模板工厂
private final Options options;//一些超时时间配置,各个粒度
private final ExceptionPropagationPolicy propagationPolicy;
private final Decoder decoder;//解码器,一般不用这个,有下面的处理器
private final AsyncResponseHandler asyncResponseHandler;//处理器
/*
Fegin完成api发送的组件的具体实现类全部由外部定制
*/
private SynchronousMethodHandler(Target<?> target, Client client, Retryer retryer,
List<RequestInterceptor> requestInterceptors, Logger logger,
Logger.Level logLevel, MethodMetadata metadata,
RequestTemplate.Factory buildTemplateFromArgs, Options options,
Decoder decoder, ErrorDecoder errorDecoder, boolean decode404,
boolean closeAfterDecode, ExceptionPropagationPolicy propagationPolicy,
boolean forceDecoding) {
this.target = checkNotNull(target, "target");
this.client = checkNotNull(client, "client for %s", target);
this.retryer = checkNotNull(retryer, "retryer for %s", target);
this.requestInterceptors =
checkNotNull(requestInterceptors, "requestInterceptors for %s", target);
this.logger = checkNotNull(logger, "logger for %s", target);
this.logLevel = checkNotNull(logLevel, "logLevel for %s", target);
this.metadata = checkNotNull(metadata, "metadata for %s", target);
this.buildTemplateFromArgs = checkNotNull(buildTemplateFromArgs, "metadata for %s", target);
this.options = checkNotNull(options, "options for %s", target);
this.propagationPolicy = propagationPolicy;
if (forceDecoding) {//默认不开启这个
this.decoder = decoder;
this.asyncResponseHandler = null;
} else {//使用响应处理器进行编解码
this.decoder = null;
this.asyncResponseHandler = new AsyncResponseHandler(logLevel, logger, decoder, errorDecoder,
decode404, closeAfterDecode);
}
}
/*
执行请求,argv请求参数
*/
@Override
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = buildTemplateFromArgs.create(argv);
Options options = findOptions(argv);
Retryer retryer = this.retryer.clone();
while (true) {
try {
return executeAndDecode(template, options);
} catch (RetryableException e) {
try {
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
Throwable cause = th.getCause();
if (propagationPolicy == UNWRAP && cause != null) {
throw cause;
} else {
throw th;
}
}
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
/*
利用template执行请求拦截连,然后返回最终的request实体
*/
Request request = targetRequest(template);
Response response;
long start = System.nanoTime();//计算时间
try {
/*
利用网络请求类发起请求
然后将请求和响应组成在一起返回response
*/
response = client.execute(request, options);
response = response.toBuilder()
.request(request)
.requestTemplate(template)
.build();
} catch (IOException e) {
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
}
throw errorExecuting(request, e);
}
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);//计算时间
/*
一般不用这个
*/
if (decoder != null)
return decoder.decode(response, metadata.returnType());
/*
调用处理器
*/
CompletableFuture<Object> resultFuture = new CompletableFuture<>();
asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,
metadata.returnType(),
elapsedTime);
try {
if (!resultFuture.isDone())
throw new IllegalStateException("Response handling not done");
return resultFuture.join();
} catch (CompletionException e) {
Throwable cause = e.getCause();
if (cause != null)
throw cause;
throw e;
}
}
Request targetRequest(RequestTemplate template) {
for (RequestInterceptor interceptor : requestInterceptors) {
interceptor.apply(template);
}
return target.apply(template);
}
}
AsyncResponseHandler ——响应结果处理层
class AsyncResponseHandler {
private static final long MAX_RESPONSE_BUFFER_SIZE = 8192L;
/*
处理的组件主要是就是编辑码组件
*/
private final Level logLevel;
private final Logger logger;
private final Decoder decoder;
private final ErrorDecoder errorDecoder;
private final boolean decode404;
private final boolean closeAfterDecode;
AsyncResponseHandler(Level logLevel, Logger logger, Decoder decoder, ErrorDecoder errorDecoder,
boolean decode404, boolean closeAfterDecode) {
super();
this.logLevel = logLevel;
this.logger = logger;
this.decoder = decoder;
this.errorDecoder = errorDecoder;
this.decode404 = decode404;
this.closeAfterDecode = closeAfterDecode;
}
/*
判断是否没返回值
*/
boolean isVoidType(Type returnType) {
return Void.class == returnType || void.class == returnType;
}
void handleResponse(CompletableFuture<Object> resultFuture,
String configKey,
Response response,
Type returnType,
long elapsedTime) {
boolean shouldClose = true;
try {
if (Response.class == returnType) {
/*
对于一些空情况的优先处理
*/
if (response.body() == null) {
resultFuture.complete(response);
} else if (response.body().length() == null
|| response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
shouldClose = false;
resultFuture.complete(response);
} else {
final byte[] bodyData = Util.toByteArray(response.body().asInputStream());
resultFuture.complete(response.toBuilder().body(bodyData).build());
}
}
/*
http状态码200-300则调用正常的解析器
*/
else if (response.status() >= 200 && response.status() < 300) {
/*
无返回值处理
*/
if (isVoidType(returnType)) {
resultFuture.complete(null);
}
/*
有返回值处理
*/
else {
final Object result = decode(response, returnType);
shouldClose = closeAfterDecode;
resultFuture.complete(result);
}
}
/*
404
*/
else if (decode404 && response.status() == 404 && !isVoidType(returnType)) {
final Object result = decode(response, returnType);
shouldClose = closeAfterDecode;
resultFuture.complete(result);
}
/*
异常解析器
*/
else {
resultFuture.completeExceptionally(errorDecoder.decode(configKey, response));
}
} catch (final IOException e) {
if (logLevel != Level.NONE) {
logger.logIOException(configKey, logLevel, e, elapsedTime);
}
resultFuture.completeExceptionally(errorReading(response.request(), response, e));
} catch (final Exception e) {
resultFuture.completeExceptionally(e);
} finally {
if (shouldClose) {
ensureClosed(response.body());
}
}
Object decode(Response response, Type type) throws IOException {
/*
调用解析器返回Object给到用到的地方
*/
try {
return decoder.decode(response, type);
} catch (final FeignException e) {
throw e;
} catch (final RuntimeException e) {
throw new DecodeException(response.status(), e.getMessage(), response.request(), e);
}
}
}
默认的解码器
RequestTemplate ——请求目标组件
框架一般都喜欢将单值装饰城对象,以方便面向对象的扩展
public final class RequestTemplate implements Serializable {
private static final Pattern QUERY_STRING_PATTERN = Pattern.compile("(?<!\\{)\\?");
private final Map<String, QueryTemplate> queries = new LinkedHashMap<>();//查询参数封装
private final Map<String, HeaderTemplate> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);//请求头封装
private boolean resolved = false;
private UriTemplate uriTemplate;//请求地址封装//
private BodyTemplate bodyTemplate;//请求body封装//
private HttpMethod method;//请求方式封装
private transient Charset charset = Util.UTF_8;//字符集
private Request.Body body = Request.Body.empty();
private boolean decodeSlash = true;
private CollectionFormat collectionFormat = CollectionFormat.EXPLODED;
private MethodMetadata methodMetadata;//接口方法的核心数据
private Target<?> feignTarget;//代理对象的保存
}