javascript
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设计原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Eclipse 从git导入maven多
- 下一篇: java 自适应响应式 网站 源码 SS