什么是Feign?

电子商务平台源码请加企鹅求求:一零三八七七四六二六。Feign 的英文表意为“假装,伪装,变形”, 是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直接调用。Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观。

Feign被广泛应用在Spring Cloud 的解决方案中,是学习基于Spring Cloud 微服务架构不可或缺的重要组件。

1、如何启用

启动配置上检查是否有@EnableFeignClients注解,如果有该注解,则开启包扫描,扫描被@FeignClient注解接口。扫描出该注解后,通过beanDefinition注入到IOC容器中,方便后续被调用使用。

在FeignClientsRegistrar中,registerFeignClients()完成了注册feign的操作。

public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {ClassPathScanningCandidateComponentProvider scanner = this.getScanner();scanner.setResourceLoader(this.resourceLoader);Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());......//遍历该项目所需调用的服务
Iterator var17 = ((Set)basePackages).iterator();while(var17.hasNext()) {String basePackage = (String)var17.next();Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);Iterator var21 = candidateComponents.iterator();while(var21.hasNext()) {BeanDefinition candidateComponent = (BeanDefinition)var21.next();if (candidateComponent instanceof AnnotatedBeanDefinition) {AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition)candidateComponent;//获取feign中的详细信息AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());String name = this.getClientName(attributes);//注册配置信息this.registerClientConfiguration(registry, name, attributes.get("configuration"));//注册feign客户端this.registerFeignClient(registry, annotationMetadata, attributes);}}}}
复制代码

注册feign客户端,包括使用注解时配置的所有信息。

private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {String className = annotationMetadata.getClassName();BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);this.validate(attributes);definition.addPropertyValue("url", this.getUrl(attributes));definition.addPropertyValue("path", this.getPath(attributes));String name = this.getName(attributes);definition.addPropertyValue("name", name);definition.addPropertyValue("type", className);definition.addPropertyValue("decode404", attributes.get("decode404"));definition.addPropertyValue("fallback", attributes.get("fallback"));definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));definition.setAutowireMode(2);String alias = name + "FeignClient";AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();boolean primary = ((Boolean)attributes.get("primary")).booleanValue();beanDefinition.setPrimary(primary);String qualifier = this.getQualifier(attributes);if (StringUtils.hasText(qualifier)) {alias = qualifier;}BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[]{alias});BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);}
复制代码

2、如何发起请求

ReflectiveFeign内部使用了jdk的动态代理为目标接口生成了一个动态代理类,这里会生成一个InvocationHandler(jdk动态代理原理)统一的方法拦截器,同时为接口的每个方法生成一个SynchronousMethodHandler拦截器,并解析方法上的 元数据,生成一个http请求模板。

在SynchronousMethodHandler类中生成RequestTemplate发起请求。

 public Object invoke(Object[] argv) throws Throwable {RequestTemplate template = buildTemplateFromArgs.create(argv);Retryer retryer = this.retryer.clone();while (true) {try {return executeAndDecode(template);} catch (RetryableException e) {retryer.continueOrPropagate(e);if (logLevel != Logger.Level.NONE) {logger.logRetry(metadata.configKey(), logLevel);}continue;}}}
复制代码
 Object executeAndDecode(RequestTemplate template) throws Throwable {Request request = targetRequest(template);Response response;long start = System.nanoTime();try {response = client.execute(request, options);// ensure the request is set. TODO: remove in Feign 10response.toBuilder().request(request).build();} catch (IOException e) {if (logLevel != Logger.Level.NONE) {logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));}throw errorExecuting(request, e);}}
复制代码

发送http请求

 @Overridepublic Response execute(Request request, Options options) throws IOException {HttpURLConnection connection = convertAndSend(request, options);return convertResponse(connection).toBuilder().request(request).build();}HttpURLConnection convertAndSend(Request request, Options options) throws IOException {final HttpURLConnectionconnection =(HttpURLConnection) new URL(request.url()).openConnection();if (connection instanceof HttpsURLConnection) {HttpsURLConnection sslCon = (HttpsURLConnection) connection;if (sslContextFactory != null) {sslCon.setSSLSocketFactory(sslContextFactory);}if (hostnameVerifier != null) {sslCon.setHostnameVerifier(hostnameVerifier);}}connection.setConnectTimeout(options.connectTimeoutMillis());connection.setReadTimeout(options.readTimeoutMillis());connection.setAllowUserInteraction(false);connection.setInstanceFollowRedirects(true);connection.setRequestMethod(request.method());Collection<String> contentEncodingValues = request.headers().get(CONTENT_ENCODING);booleangzipEncodedRequest =contentEncodingValues != null && contentEncodingValues.contains(ENCODING_GZIP);booleandeflateEncodedRequest =contentEncodingValues != null && contentEncodingValues.contains(ENCODING_DEFLATE);boolean hasAcceptHeader = false;Integer contentLength = null;for (String field : request.headers().keySet()) {if (field.equalsIgnoreCase("Accept")) {hasAcceptHeader = true;}for (String value : request.headers().get(field)) {if (field.equals(CONTENT_LENGTH)) {if (!gzipEncodedRequest && !deflateEncodedRequest) {contentLength = Integer.valueOf(value);connection.addRequestProperty(field, value);}} else {connection.addRequestProperty(field, value);}}}// Some servers choke on the default accept string.if (!hasAcceptHeader) {connection.addRequestProperty("Accept", "*/*");}if (request.body() != null) {if (contentLength != null) {connection.setFixedLengthStreamingMode(contentLength);} else {connection.setChunkedStreamingMode(8196);}connection.setDoOutput(true);OutputStream out = connection.getOutputStream();if (gzipEncodedRequest) {out = new GZIPOutputStream(out);} else if (deflateEncodedRequest) {out = new DeflaterOutputStream(out);}try {out.write(request.body());} finally {try {out.close();} catch (IOException suppressed) { // NOPMD}}}return connection;}
复制代码

java B2B2C Springboot电子商务平台源码

转载于:https://juejin.im/post/5cb921146fb9a068a84fe3d2

java B2B2C Springboot电子商务平台源码-Feign设计原理相关推荐

  1. java B2B2C Springboot电子商务平台源码-Feign 基本使用

    1. [microcloud-consumer-feign]为了可以使用到 feign 支持,需要修改 pom.xml 配置文件,引入相关依赖包:需要JAVA Spring Cloud大型企业分布式微 ...

  2. java B2B2C Springcloud电子商务平台源码 -Feign之源码解析

    什么是Feign Feign是受到Retrofit,JAXRS-2.0和WebSocket的影响,它是一个jav的到http客户端绑定的开源项目. Feign的主要目标是将Java Http 客户端变 ...

  3. java B2B2C Springboot电子商务平台源码-SSO单点登录之OAuth2.0登录认证

    之前写了很多关于spring cloud的文章,今天我们对OAuth2.0的整合方式做一下笔记,首先我从网上找了一些关于OAuth2.0的一些基础知识点,帮助大家回顾一下知识点: 一.oauth中的角 ...

  4. java B2B2C Springcloud电子商务平台源码-服务网关过滤器

    过滤器作用 我们的微服务应用提供的接口就可以通过统一的API网关入口被客户端访问到了.但是,每个客户端用户请求微服务应用提供的接口时,它们的访问权限往往都需要有一定的限制,系统并不会将所有的微服务接口 ...

  5. java B2B2C Springcloud电子商务平台源码-RabbitMQ基础概念...

    RabbitMQ是一个由erlang开发的AMQP的开源实现. 需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六 AMQP,即Adva ...

  6. java B2B2C Springcloud电子商务平台源码-security简单使用

    security的简单原理: 需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码:壹零叁八柒柒肆六二六 使用众多的拦截器对url拦截,以此来管理权限.但是这么 ...

  7. java B2B2C Springcloud电子商务平台源码

    鸿鹄云商大型企业分布式互联网电子商务平台,推出PC+微信+APP+云服务的云商平台系统,其中包括B2B.B2C.C2C.O2O.新零售.直播电商等子平台.愿意了解源码的朋友直接求求交流分享技术:二一四 ...

  8. java B2B2C Springcloud电子商务平台源码------Hystrix的缓存使用

    一 介绍 在高并发的场景之下,Hystrix中提供了请求缓存的功能,可以方便地开启和使用请求缓存来优化系统,达到减轻高并发时请求线程的消耗.降低请求响应时间的效果.愿意了解源码的朋友直接求求交流分享技 ...

  9. java B2B2C springmvc mybatis电子商务平台源码

    用java实施的电子商务平台太少了,使用spring cloud技术构建的b2b2c电子商务平台更少,大型企业分布式互联网电子商务平台,推出PC+微信+APP+云服务的云商平台系统,其中包括B2B.B ...

最新文章

  1. 在线实时大数据平台Storm集成redis开发(分布锁)
  2. boost::gil::color_spaces_are_compatible用法的测试程序
  3. Java面向对象(四)final关键字
  4. 小甲鱼python视频第八讲(课后习题)
  5. P3750-[六省联考2017]分手是祝愿【期望dp】
  6. C# Task异步编程
  7. Oracle Linux 6.5 RPM安装Mysql 5.7.11
  8. C++中4种方式把字符串和数字连接起来(转载)
  9. nodpad 设置护眼_Notepad++更改背景颜色(护眼色)
  10. python的三种数据类型列举_3.Python编程之数据类型
  11. oracle创建表之前判断表是否存在,如果存在则删除已有表
  12. c++多线程——数据共享
  13. TFS无法连接:TF31002
  14. 一阶广义差分模型_实验五 自相关性 -
  15. JAVA用cmd找不到字符_cmd中输入java找不到文件解决方法
  16. python编写摇骰子游戏_python摇骰子猜大小的小游戏
  17. Java程序员面试全集(上)
  18. 聚齐乐服务器维护时间多久,9月19日服务器例行维护更新公告(已完成)
  19. 【微信小程序】video视频(77/100)
  20. 码云(Gitee)创建SSH KEY以及查看用户名密码

热门文章

  1. POJ-1322 Chocolate 动态规划
  2. eclipse 导入myeclipse web项目
  3. Across the universe
  4. 再读《精通css》06:背景图片
  5. 16个经典面试问题回答思路[求职者必看]
  6. UA MATH524 复变函数3 复变函数的极限与可微性
  7. Dockerfile命令详解
  8. RequestAnimationFrame知多少?
  9. jdk官网历史版本下载Oracle账号密码
  10. 输入十个学生的成绩,判断及格不及格人数,得到不及格人的学号