2021年7月14日星期三

Feign使用分析

feign使用

在实现的效果上来说Feign = RestTemplate+Ribbon+Hystrix

Feign实现RestTemplate+Ribbon效果

Feign实现RestTemplate+Ribbon效果,只需要以下几步
在springcloud项目调用方的pom文件中加入openFeign的配置

  <dependency>   <groupId>org.springframework.cloud</groupId>   <artifactId>spring-cloud-starter-openfeign</artifactId>  </dependency>

在启动类中加入@EnableFeignClients
同时使用接口声明的方式来实现接口调用

@FeignClient(name = "zhao-service-resume")public interface ResumeFeignClient { @GetMapping("/resume/openstate/{userId}") public Integer findDefaultResumeState(@PathVariable Long userId) ;}

这个接口的声明与被调用方的实现完全一样,我们需要在声明时@FeignClient(name = "zhao-service-resume")声明被调用的服务,即可按照默认的方式进行调用
使用单元测试测试即可测试到负载均衡的效果,访问两次,分别访问到8081和8082端口的服务

@RunWith(SpringRunner.class)@SpringBootTest(classes = DeliverApplication8091.class)public class FeignTest { @Autowired ResumeFeignClient feignClient; @Test public void feignTest(){  Integer port = feignClient.findDefaultResumeState(2195321L);  System.out.println("测试的结果"+port);  }}

那么如何在配置类中配置负载均衡呢?格式如下,同时我们还配置了请求的超时时间,在没有配置hystrix的情况下,会出现超时的情况,

zhao-service-resume: ribbon: #请求连接超时时间 ConnectTimeout: 2000 #请求处理超时时间 ReadTimeout: 5000 #对所有操作都进⾏重试 OkToRetryOnAllOperations: true####根据如上配置,当访问到故障请求的时候,它会再尝试访问⼀次当前实例(次数由MaxAutoRetries配置), ####如果不⾏,就换⼀个实例进⾏访问,如果还不⾏,再换⼀次实例访问(更换次数由MaxAutoRetriesNextServer配置),####如果依然不⾏,返回失败信息。 MaxAutoRetries: 0 #对当前选中实例重试次数,不包括第⼀次调⽤ MaxAutoRetriesNextServer: 0 #切换实例的重试次数 NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #负载策略调整

超时的报错feign.RetryableException: Read timed out executing GET id="feign实现hystrix效果">Feign实现Hystrix效果

首先是先开启熔断器

feign: hystrix: enabled: true

接着增加超时处理逻辑的相关配置

hystrix: command: default:  execution:  isolation:   thread:   timeoutInMilliseconds: 15000

但是即使我在被调用方只线程休眠了十秒,程序依然被熔断了。查阅资料表明,Hystrix将采用feign和hystrix超时时间中较小的那个进行超时判定
file
增加降级兜底方法

@Componentpublic class FeignClientFallBack implements ResumeFeignClient { @Override public Integer findDefaultResumeState(Long userId) {  return -1; }}

在调用方增加降级配置

@FeignClient(name = "zhao-service-resume",fallback = FeignClientFallBack.class)public interface ResumeFeignClient { @GetMapping("/resume/openstate/{userId}") public Integer findDefaultResumeState(@PathVariable Long userId) ;}

同时可以在@FeignClient中增加path属性,将方法上的公共路径提取到类中

Feign使用上的其他特性

Feign请求压缩和响应压缩配置

配置属性如下

feign: compression: request:  enabled: true  min-request-size: 2048  mime-types: text/html,application/

以上配置包含的两个属性,min-request-size: 2048表示开启压缩的最小值为2048字节,mime-types为支持压缩的数据类型,当前的这几种类型未默认值

Feign请求日志配置

首先在yml中设置具体的类的日志响应级别

logging: level:# Feign⽇志只会对⽇志级别为debug的做出响应 com.lagou.edu.controller.service.ResumeServiceFeignClient:debug

然后就是针对feign的log的配置

import feign.Logger;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class FeignConfig { @Bean Logger.Level feignLevel(){  return Logger.Level.FULL; }}

需要注意的是,此处引入的是feign.Logger,此处表示的含义是feign将会打印请求的所有信息如下
file

Feign源码简要分析

还是依据前文,依照启动类注解和spring.factories中配置的自动配置类来进行分析,首先我们看@EnableFeignClients注解中的FeignClientsRegistrar的具体内容,实现的依然是Spring中的注入beanDefinition的内容

	@Override	public void registerBeanDefinitions(AnnotationMetadata metadata,			BeanDefinitionRegistry registry) {		registerDefaultConfiguration(metadata, registry);		registerFeignClients(metadata, registry);	}

registerDefaultConfiguration注入默认配置我们基本可以确定就是加入一些默认配置,而registerFeignClients就是最终实现逻辑的地方。而最终实现逻辑的地方是在该方法下的

private void registerFeignClient(BeanDefinitionRegistry registry,			AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {		String className = annotationMetadata.getClassName();		BeanDefinitionBuilder definition = BeanDefinitionBuilder				.genericBeanDefinition(FeignClientFactoryBean.class);		validate(attributes);		definition.addPropertyValue("url", getUrl(attributes));		definition.addPropertyValue("path", getPath(attributes));		String name = getName(attributes);		definition.addPropertyValue("name", name);		String contextId = getContextId(attributes);		definition.addPropertyValue("contextId", contextId);		definition.addPropertyValue("type", className);		definition.addPropertyValue("decode404", attributes.get("decode404"));		definition.addPropertyValue("fallback", attributes.get("fallback"));		definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));		definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);		String alias = contextId + "FeignClient";		AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();		boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null		beanDefinition.setPrimary(primary);		String qualifier = getQualifier(attributes);		if (StringUtils.hasText(qualifier)) {			alias = qualifier;		}		BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,				new String[] { alias });		BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);	}

而这个类都依赖于 BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);几乎可以确定注入的时候就是FeignClientFactoryBean这个工厂Bean在起作用,那么我们在进入里面看一看,工厂Bean最重要的就是getObject返回的类型情况

@Override	public Object getObject() throws Exception {		return getTarget();	}	/**	 * @param <T> the target type of the Feign client	 * @return a {@link Feign} client created with the specified data and the context information	 */	<T> T getTarget() {		FeignContext context = applicationContext.getBean(FeignContext.class);		Feign.Builder builder = feign(context);		if (!StringUtils.hasText(this.url)) {			if (!this.name.startsWith("http")) {				url = "http://" + this.name;			}			else {				url = this.name;			}			url += cleanPath();			return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type,					this.name, url));		}		if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {			this.url = "http://" + this.url;		}		String url = this.url + cleanPath();		Client client = getOptional(context, Client.class);		if (client != null) {			if (client instanceof LoadBalancerFeignClient) {				// not load balancing because we have a url,				// but ribbon is on the classpath, so unwrap				client = ((LoadBalancerFeignClient)client).getDelegate();			}			builder.client(client);		}		Targeter targeter = get(context, Targeter.class);		return (T) targeter.target(this, builder, context, new HardCodedTarget<>(				this.type, this.name, url));	}

在上述代码中,基本上就是构造客户端并调用的过程,那么最关键的就是实现了Ribbon功能的负载均衡的loadBalance操作中内容

	protected <T> T loadBalance(Feign.Builder builder, FeignContext context,			HardCodedTarget<T> target) {		Client client = getOptional(context, Client.class);		if (client != null) {			builder.client(client);			Targeter targeter = get(context, Targeter.class);			return targeter.target(this, builder, context, target);		}		throw new IllegalStateException(				"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");	}

而 targeter.target这段最后都会执行到feign类中的这个方法中

 public <T> T target(Target<T> target) {  return build().newInstance(target); }

关注到newInstance方法发现最终实现时在ReflectiveFeign类中

 @Override public <T> T newInstance(Target<T> targe......

原文转载:http://www.shaoqun.com/a/877492.html

跨境电商:https://www.ikjzd.com/

naning9韩国官网:https://www.ikjzd.com/w/2401

picitup:https://www.ikjzd.com/w/446

feedly:https://www.ikjzd.com/w/754


feign使用在实现的效果上来说Feign=RestTemplate+Ribbon+HystrixFeign实现RestTemplate+Ribbon效果Feign实现RestTemplate+Ribbon效果,只需要以下几步在springcloud项目调用方的pom文件中加入openFeign的配置<dependency><groupId>org.springframew
电霸:https://www.ikjzd.com/w/2597
蜜芽宝贝:https://www.ikjzd.com/w/1320
2021春节最佳旅游线路 春节最北和最南两条绝佳路线精选:http://www.30bags.com/a/433061.html
2021春天去哪里看杏花?盘点全国杏花观赏地:http://www.30bags.com/a/434427.html
2021春湾石林灯光节举办多久?灯光节免费开放吗?:http://www.30bags.com/a/432038.html
2021春湾桃花3月盛开的吗?阳春春湾桃花3月份开的怎么样?:http://www.30bags.com/a/432116.html
粗大从后面狠狠挺进 水中欢爱猛烈撞击:http://lady.shaoqun.com/a/248412.html
口述:公公竟然偷听我和丈夫爱爱公公老公爱爱:http://lady.shaoqun.com/m/a/33727.html
你能不能瞥一眼这些常见的立场,并把它做对?:http://lady.shaoqun.com/a/422142.html
亚马逊等平台1254家店铺被起诉侵权,卖家被冻结3000万元:保护好商标专利迫在眉睫:https://www.ikjzd.com/articles/146616
一些女性产品实际上是男性为了自己使用而发明的:http://lady.shaoqun.com/a/422143.html
提高性生活质量的11个细节:http://lady.shaoqun.com/a/422144.html

没有评论:

发表评论