热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

微服务架构专题五:SpringCloud组件:feign

微服务架构专题五:Spring-Cloud组件:feign,Go语言社区,Golang程序员人脉社



文章目录


    • 一、feign是什么 :
    • 二、feign 能干什么:
    • 三、如何使用?
    • 四、Feign 如何结合 Ribbon 切换均衡算法
    • 五、Feign整合了Hystrix,具有熔断的能力 之Fallback
    • (一)Fallback-实现Feign接口
    • (二)FallbackFactory工厂
    • 六、使用线程池优化feign的http请求组件


一、feign是什么 :

Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单, 它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。SpringCloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
简而言之:
Feign 采用的是基于接口的注解
Feign 整合了ribbon,具有负载均衡的能力
整合了Hystrix,具有熔断的能力


二、feign 能干什么:

Feign旨在使编写Java Http客户端变得更容易。 前面在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。


三、如何使用?

1、在客户端(User)引入依赖:

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

2、在启动类上面加上注解:@EnableFeignClients


@SpringBootApplication
@EnableEurekaClient
@RibbonClients({
@RibbonClient(name = "SERVER-ORDER",configuration = OrderRuleConfig.class),
@RibbonClient(name = "SERVER-POWER",configuration = PowerRuleConfig.class)
})
@EnableFeignClients
public class AppUserClient {
public static void main(String[] args) {
SpringApplication.run(AppUserClient.class);
}
}

3、然后编写一个service类加上@FeignClient()注解 参数就是你的微服务名字

@FeignClient(name = "SERVER-POWER")
public interface PowerFeignClient {
@RequestMapping("/getPower.do")
Object getPower();
}

4、下面是调用代码:

@RestController
public class UserFeignController {
@Autowired
private PowerFeignClient powerFeignClient;
@RequestMapping("/getFeignPower.do")
public R getFeignPower(){
return R.success("操作成功",powerFeignClient.getPower());
}

这里可以拿微服务架专题四中RestTemplate做对比 可以看看2者区别。


四、Feign 如何结合 Ribbon 切换均衡算法

Feign集成了Ribbon利用Ribbon维护了服务列表信息,并且融合了Ribbon的负载均衡配置,也就是说之前自定义的负载均衡也有效,这里需要你们自己跑一遍理解一下。而与Ribbon不同的是,通过feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用;

MICROSERVICE-ORDER 表示作用到哪个微服务,com.netflix.loadbalancer.RandomRule 即前面介绍 Ribbon 时里面的随机策略,当然,我们也可以指定为其他策略,包括我们自己定义的,只要把相应的包路径写到这即可,很方便。
也很简单,我们可以在 application.properties 配置文件中来指定,如下:

# feign和ribbon结合,指定策略。feign默认的是轮询的策略,这里的配置可以自定义
MICROSERVICE-ORDER.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RoundRobinRule
MICROSERVICE-ORDER.ribbon.COnnectTimeout=500 #请求连接超时时间
MICROSERVICE-ORDER.ribbon.ReadTimeout=1000 #请求处理的超时时间
MICROSERVICE-ORDER.ribbon.OkToRetryOnAllOperations=true #对所有请求都进行重试
MICROSERVICE-ORDER.ribbon.MaxAutoRetriesNextServer=2 #切换实例的重试次数
MICROSERVICE-ORDER.ribbon.MaxAutoRetries=1 #对当前实例的重试次数

这里我们可以看到ribbon的策略主要有以下几种:

com.netflix.loadbalancer.RandomRule #配置规则 随机
com.netflix.loadbalancer.RoundRobinRule #配置规则 轮询
com.netflix.loadbalancer.RetryRule #配置规则 重试
com.netflix.loadbalancer.WeightedResponseTimeRule #配置规则 响应时间权重
com.netflix.loadbalancer.BestAvailableRule #配置规则 最空闲连接策略

随机:几个提供者间随机访问
轮询:轮流访问
重试:在一段时间内通过RoundRobinRule选择服务实例,一段时间内没有选择出服务则线程终止
响应时间权重:根据平均响应时间来计算权重


五、Feign整合了Hystrix,具有熔断的能力 之Fallback

在网络请求时,可能会出现异常请求,如果还想再异常情况下使系统可用,那么就需要容错处理,比如:网络请求超时时给用户提示“稍后重试”或使用本地快照数据等等。

Spring Cloud Feign HTTP请求异常Fallback容错机制,它是基于Hystrix实现的,所以要通过配置参数feign.hystrix.enabled=true开启该功能,及其两种实现方式。

Spring Cloud Feign就是通过Fallback实现的,有两种方式:

1、@FeignClient.fallback = UserFeignFallback.class指定一个实现Feign接口的实现类。

2、@FeignClient.fallbackFactory = UserFeignFactory.class指定一个实现FallbackFactory工厂接口类


(一)Fallback-实现Feign接口

UserFeignFallback回调实现,由spring创建使用@Component(其他的注册也可以)注解
HystrixTargeter.targetWithFallback方法实现了@FeignClient.fallback处理逻辑,通过源码可以知道UserFeignFallback回调类是从Spring容器中获取的,所以UserFeignFallback由spring创建。

UserFeignService:

@FeignClient(value = "HOUSE-USER",fallbackFactory = UserClientFallBack.class)
public interface UserFeignService {
@RequestMapping("/user/getById")
User getUserDetailById(@RequestParam("id")Long id);
}

UserClientFallBack:

@Component
public class UserClientFallBack implements UserFeignService {
@Override
public User getUserDetailById(Long id) {
return null;
}
}

(二)FallbackFactory工厂

上面的实现方式简单,但是获取不到HTTP请求错误状态码和信息 ,这时就可以使用工厂模式来实现Fallback
同样工厂实现类也要交由spring管理,同时结合UserFeignFallback使用,这里需要注意的create方法返回值类型一定要实现Feign接口,否则会报错。

在feign中开启hystrix功能,默认情况下feign不开启hystrix功能,添加配置开启
feign.hystrix.enabled=true

service类:

@FeignClient(value = "HOUSE-COMMENT",fallbackFactory = CommentFeignFallBackFactory.class)
public interface CommentFeignService {
@RequestMapping("/comment/add")
void addComment(@RequestBody CommentReq commentReq);

@RequestMapping("/blog/list")
RestResponse<ListResponse<Blog>> getBlogs(@RequestBody BlogQueryReq blogQueryReq);
@RequestMapping("/blog/one")
RestResponse<Blog> getBlog(@RequestParam("id") int id);

@RequestMapping(value = "/group/{groupId}", method = RequestMethod.PUT)
void update(@PathVariable("groupId") Integer groupId, @RequestParam("groupName") String groupName)

}

方式一:
该方式可以获取到异常信息throwable.printStackTrace();
CommentFeignFallBackFactory类

@Component
public class CommentFeignFallBackFactory implements FallbackFactory<CommentFeignService> {
@Override
public CommentFeignService create(Throwable throwable) {
return new CommentFeignService(){
@Override
public void addComment(CommentReq commentReq) {
throw new RuntimeException(throwable.getMessage());
}
@Override
public RestResponse<ListResponse<Blog>> getBlogs(BlogQueryReq blogQueryReq) {
return new RestResponse<>();
}
@Override
public RestResponse<Blog> getBlog(int id) {
throw new RuntimeException("服务异常,请稍后重试!");
}
@Override
public void update() {
throw new RuntimeException("服务异常,请稍后重试!");
}
};
}
}

方式二:
CommentFeignServiceHystrix:

@Component
public class CommentFeignServiceHystrix implements CommentFeignService {
@Override
public void addComment(CommentReq commentReq) {
throw new RuntimeException("服务异常,请稍后重试!");
}
@Override
public RestResponse<List<Comment>> listComment(CommentReq commentReq) {
return new RestResponse<>();
}
@Override
public RestResponse<ListResponse<Blog>> getBlogs(BlogQueryReq blogQueryReq) {
return new RestResponse<>();
}
@Override
public RestResponse<Blog> getBlog(int id) {
throw new RuntimeException("服务异常,请稍后重试!");
}
}

CommentFeignFallBackFactory:

@Component
public class CommentFeignFallBackFactory implements FallbackFactory<CommentFeignService> {
@Override
public CommentFeignService create(Throwable throwable) {
return new CommentFeignServiceHystrix();
}
}

六、使用线程池优化feign的http请求组件


  1. 概述
    在默认情况下 spring cloud feign在进行各个子服务之间的调用时,http组件使用的是jdk的HttpURLConnection,没有使用线程池。效率非常低。
    为了提高效率,可以通过连接池提高效率,本节我们使用appache httpclient做为连接池。配置OkHttpClient连接池,也是类似的方法,这里略。

  2. pom.xml中引入feign-httpclient.jar



io.github.openfeign
feign-httpclient



我在配置时遇到了一个坑,不要随便指定feign-httpclient的version,否则会冲突报错,运行是报
在这里插入图片描述


  1. 配置参数
    只需在application.properties中新增配置项,启动httpclient,就可以实现httpclient替换urlconnection。
    feign.httpclient.enabled=true

  2. 自定义配置类
    使用配置类,生成HttpClient 对象。因为使用PoolingHttpClientConnectionManager连接池,我们需要启动定时器,定时回收过期的连接。配置定时回收连接池的原因,见问题备忘: httpclient连接池异常引发的惨案。
    http pool setting:

#http pool setting
http.pool.conn.maxTotal=500
http.pool.conn.defaultMaxPerRoute=100
http.pool.conn.cOnnectTimeout=10000
http.pool.conn.cOnnectionRequestTimeout=1000
http.pool.conn.socketTimeout=65000
http.pool.conn.validateAfterInactivity=2000
http.pool.conn.maxCOnnPerRoute=10
http.pool.conn.maxCOnnTotaol=50

HttpClientProperties:

@Component
@ConfigurationProperties(prefix = "http.pool.conn")
@Data
public class HttpClientProperties {
private String agent = "agent";
private Integer maxTotal;
private Integer defaultMaxPerRoute;
private Integer connectTimeout;
private Integer connectionRequestTimeout;
private Integer socketTimeout;
private Integer validateAfterInactivity;
private Integer maxConnPerRoute;
private Integer maxConnTotaol;
}

FeignConfig:配置httpclient和 访问https地址

@Configuration
public class FeignConfig {
@Autowired
private HttpClientProperties httpPoolProperties;
/**
* 配置httpclient
* @return
*/
@Bean
public HttpClient httpClient(){
System.out.println("init feign httpclient configuration " );
// 生成默认请求配置
RequestConfig requestCOnfig= RequestConfig.custom()
//服务器返回数据(response)的时间,超过抛出read timeout
.setSocketTimeout(httpPoolProperties.getSocketTimeout())
//连接上服务器(握手成功)的时间,超出抛出connect timeout
.setConnectTimeout(httpPoolProperties.getConnectTimeout())
//从连接池中获取连接的超时时间,超时间未拿到可用连接,会抛出ConnectionPoolTimeoutException
.setConnectionRequestTimeout(httpPoolProperties.getConnectionRequestTimeout())
.build();
// 连接池配置
// 长连接保持30秒
PoolingHttpClientConnectionManager cOnnectionManager= new PoolingHttpClientConnectionManager(30, TimeUnit.MILLISECONDS);
connectionManager.setMaxTotal(httpPoolProperties.getMaxTotal());// 总连接数
connectionManager.setDefaultMaxPerRoute(httpPoolProperties.getDefaultMaxPerRoute());// 同路由的并发数
connectionManager.setValidateAfterInactivity(httpPoolProperties.getValidateAfterInactivity());
// httpclient 配置
HttpClient client
= HttpClientBuilder.create()
// 保持长连接配置,需要在头添加Keep-Alive
.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
.setDefaultRequestConfig(requestConfig)//设置requestConfig
.setUserAgent(httpPoolProperties.getAgent())//设置User-Agent
.setMaxConnPerRoute(httpPoolProperties.getMaxConnPerRoute())//设置一个远端IP最大的连接数
.setMaxConnTotal(httpPoolProperties.getMaxConnTotaol())//设置总的连接数
//不重用连接,默认是重用,建议保持默认开启连接池,节省建立连接开销
//.setConnectionReuseStrategy(new NoConnectionReuseStrategy())
.setConnectionManager(connectionManager)
.build();
// 启动定时器,定时回收过期的连接
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// System.out.println("=====closeIdleCOnnections===");
connectionManager.closeExpiredConnections();
connectionManager.closeIdleConnections(5, TimeUnit.SECONDS);
}
}, 10 * 1000, 5 * 1000);
System.out.println("===== Apache httpclient 初始化连接池===");
return client;
}
/**
* 访问https地址
* @param cachingFactory
* @param clientFactory
* @return
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
*/
@Bean
@ConditionalOnMissingBean
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory) throws NoSuchAlgorithmException, KeyManagementException {
SSLContext ctx = SSLContext.getInstance("SSL");
X509TrustManager tm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[]{tm}, null);
return new LoadBalancerFeignClient(new Client.Default(ctx.getSocketFactory(),
new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
// TODO Auto-generated method stub
return true;
}
}) ,
cachingFactory, clientFactory);
}
}

原理:
在这里插入图片描述
按照导入从上往下的顺序:HttpClientFeignLoadBalancedConfiguration>OkHttpFeignLoadBalancedConfiguration>DefaultFeignLoadBalancedConfiguration,对应的底层http工具:httpclient>okhttp>HttpURLConnection

所以pom中引入feign-httpclient–》类路径下存在ApacheHttpClient.class–》走HttpClientFeignLoadBalancedConfiguration–》请求时走HttpClient




推荐阅读
  • k8s+springboot+Eureka如何平滑上下线服务
    k8s+springboot+Eureka如何平滑上下线服务目录服务平滑上下线-k8s版本目录“上篇介绍了springboot+Euraka服务平滑上下线的方式,有部分小伙伴反馈k ... [详细]
  • 熟练掌握Spring Cloud,终于成为Java工程师的面试门槛 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了SpringCloudRibbon部分源码相关的知识,希望对你有一定的参考价值。1:ribbon是提供通过servi ... [详细]
  • 后台自动化测试与持续部署实践
    后台自动化测试与持续部署实践https:mp.weixin.qq.comslqwGUCKZM0AvEw_xh-7BDA后台自动化测试与持续部署实践原创 腾讯程序员 腾讯技术工程 2 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • Sleuth+zipkin链路追踪SpringCloud微服务的解决方案
    在庞大的微服务群中,随着业务扩展,微服务个数增多,系统调用链路复杂化。Sleuth+zipkin是解决SpringCloud微服务定位和追踪的方案。通过TraceId将不同服务调用的日志串联起来,实现请求链路跟踪。通过Feign调用和Request传递TraceId,将整个调用链路的服务日志归组合并,提供定位和追踪的功能。 ... [详细]
  • [翻译]微服务设计模式5. 服务发现服务端服务发现
    服务之间需要互相调用,在单体架构中,服务之间的互相调用直接通过编程语言层面的方法调用就搞定了。在传统的分布式应用的部署中,服务地 ... [详细]
  • 服务网关与流量网关
    一、为什么需要服务网关1、什么是服务网关传统的单体架构中只需要开放一个服务给客户端调用,但是微服务架构中是将一个系统拆分成多个微服务,如果没有网关& ... [详细]
  • zuul 路由不生效_Zuul网关到底有何牛逼之处?竟然这么多人在用~
    作者:kosamino来源:cnblogs.comjing99p11696192.html哈喽,各位新来的小伙伴们,大家好& ... [详细]
  • TiDB | TiDB在5A级物流企业核心系统的应用与实践
    TiDB在5A级物流企业核心系统的应用与实践前言一、业务背景科捷物流概况神州金库简介二、现状与挑战神州金库现有技术体系业务挑战应对方案三、TiDB解决方案测试迁移收益问题四、说在最 ... [详细]
author-avatar
飞舞的猫2502890283
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有