java B2B2C Springboot电子商务平台源码-Feign设计原理
什么是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设计原理相关推荐
- java B2B2C Springboot电子商务平台源码-Feign 基本使用
1. [microcloud-consumer-feign]为了可以使用到 feign 支持,需要修改 pom.xml 配置文件,引入相关依赖包:需要JAVA Spring Cloud大型企业分布式微 ...
- java B2B2C Springcloud电子商务平台源码 -Feign之源码解析
什么是Feign Feign是受到Retrofit,JAXRS-2.0和WebSocket的影响,它是一个jav的到http客户端绑定的开源项目. Feign的主要目标是将Java Http 客户端变 ...
- java B2B2C Springboot电子商务平台源码-SSO单点登录之OAuth2.0登录认证
之前写了很多关于spring cloud的文章,今天我们对OAuth2.0的整合方式做一下笔记,首先我从网上找了一些关于OAuth2.0的一些基础知识点,帮助大家回顾一下知识点: 一.oauth中的角 ...
- java B2B2C Springcloud电子商务平台源码-服务网关过滤器
过滤器作用 我们的微服务应用提供的接口就可以通过统一的API网关入口被客户端访问到了.但是,每个客户端用户请求微服务应用提供的接口时,它们的访问权限往往都需要有一定的限制,系统并不会将所有的微服务接口 ...
- java B2B2C Springcloud电子商务平台源码-RabbitMQ基础概念...
RabbitMQ是一个由erlang开发的AMQP的开源实现. 需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六 AMQP,即Adva ...
- java B2B2C Springcloud电子商务平台源码-security简单使用
security的简单原理: 需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码:壹零叁八柒柒肆六二六 使用众多的拦截器对url拦截,以此来管理权限.但是这么 ...
- java B2B2C Springcloud电子商务平台源码
鸿鹄云商大型企业分布式互联网电子商务平台,推出PC+微信+APP+云服务的云商平台系统,其中包括B2B.B2C.C2C.O2O.新零售.直播电商等子平台.愿意了解源码的朋友直接求求交流分享技术:二一四 ...
- java B2B2C Springcloud电子商务平台源码------Hystrix的缓存使用
一 介绍 在高并发的场景之下,Hystrix中提供了请求缓存的功能,可以方便地开启和使用请求缓存来优化系统,达到减轻高并发时请求线程的消耗.降低请求响应时间的效果.愿意了解源码的朋友直接求求交流分享技 ...
- java B2B2C springmvc mybatis电子商务平台源码
用java实施的电子商务平台太少了,使用spring cloud技术构建的b2b2c电子商务平台更少,大型企业分布式互联网电子商务平台,推出PC+微信+APP+云服务的云商平台系统,其中包括B2B.B ...
最新文章
- 在线实时大数据平台Storm集成redis开发(分布锁)
- boost::gil::color_spaces_are_compatible用法的测试程序
- Java面向对象(四)final关键字
- 小甲鱼python视频第八讲(课后习题)
- P3750-[六省联考2017]分手是祝愿【期望dp】
- C# Task异步编程
- Oracle Linux 6.5 RPM安装Mysql 5.7.11
- C++中4种方式把字符串和数字连接起来(转载)
- nodpad 设置护眼_Notepad++更改背景颜色(护眼色)
- python的三种数据类型列举_3.Python编程之数据类型
- oracle创建表之前判断表是否存在,如果存在则删除已有表
- c++多线程——数据共享
- TFS无法连接:TF31002
- 一阶广义差分模型_实验五 自相关性 -
- JAVA用cmd找不到字符_cmd中输入java找不到文件解决方法
- python编写摇骰子游戏_python摇骰子猜大小的小游戏
- Java程序员面试全集(上)
- 聚齐乐服务器维护时间多久,9月19日服务器例行维护更新公告(已完成)
- 【微信小程序】video视频(77/100)
- 码云(Gitee)创建SSH KEY以及查看用户名密码