SpringCloud OpenFeign
1.OpenFeign 介绍
1.OpenFeign 是什么
-
OpenFeign 是个声明式 WebService 客户端,使用 OpenFeign 让编写 Web Service 客户端 更简单
-
它的使用方法是定义一个服务接口然后在上面添加注解
-
OpenFeign 也支持可拔插式的编码器和解码器。
-
Spring Cloud 对 OpenFeign 进 行 了 封 装 使 其 支 持 了 Spring MVC 标 准 注 解 和 HttpMessageConverters
-
OpenFeign 可以与 Eureka 和 Ribbon 组合使用以支持负载均衡
2.官网
地址:openFeign官网
3.Feign 和 OpenFeign 区别
Feign
1.Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端 2.Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。
3.Feign的使用方式是:使用Feign的注解定义接口,调用服务注册中心的服务
4.Feign支持的注解和用法请参考官方文档:https://github.com/OpenFeign/feign
5.Feign本身不支持Spring MVC的注解,它有一套自己的注解
6.引入依赖
<dependencies>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-bom</artifactId>
<version>??feign.version??</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
OpenFeign
1.OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解,如 @RequesMapping等等。
2.OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口
3.OpenFeign通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务
4.引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
精简一句话:OpenFeign 就是在 Feign 基础上做了加强 , 有些程序员为了方便,说 Feign 就是指的 OpenFeign
2.OpenFeign-应用实例
1.需求分析/图解
– 示意图
2.创建服务消费模块 -通过 OpenFeigen 实现远程调用的三种方式
1.通过注册中心服务发现实现远程调用
1.参考 member-service-consumer-80 创建 member-service-consumer-openfeign-80模块
2.修改 pom.xml,引入openfeign依赖
<!--引入openfeign场景启动器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
3.创建 application.yml 内容如下:
server:
port: 80
spring:
application:
name: member-service-consumer-openfeign-80
#配置eureka-client
eureka:
client:
#将自己注册到eureka-server
register-with-eureka: true
#表示从eureka-server获取注册信息
#如果是单节点是可以不配置的,但如果是集群则必须配置为true,才能配合Ribbon实现负载均衡功能
fetch-registry: true
service-url:
#表示将自己注册到哪个eureka-server
defaultZone: http://eureka9001.com:9001/eureka/,http://eureka9002.com:9002/eureka/
4.创建主启动类
//启用OpenFeignClient
@EnableFeignClients
@EnableEurekaClient
@SpringBootApplication
public class MemberConsumerOpenfeignApplication {
public static void main(String[] args) {
SpringApplication.run(MemberConsumerOpenfeignApplication.class,args);
}
}
5.创建MemberFeignService.java,
@Component
@FeignClient(value = "MEMBER-SERVICE-PROVIDER")
public interface MemberFeignService {
//定义方法-远程调用接口
/**
* 1. 远程调用的方式是get
* 2. 远程调用的url http://MEMBER-SERVICE-PROVIDER/member/get/{id}
* 3. MEMBER-SERVICE-PROVIDER 就是服务提供方在Eureka Server 注册的服务
* 4. openfeign 会根据负载均衡来决定调用10000/10002-默认是轮询
* 5. 因为openfeign 好处是支持了springmvc注解 + 接口解耦
*
* openfeign是怎么样去远程调用的呢?
* 1.注册中心通过MEMBER-SERVICE-PROVIDER服务注册名从注册中心去获取请求地址
* 192.168.79.1:member-service-provider:10002 , 192.168.79.1:member-service-provider:10001
* 2.通过springmvc注解 + 接口的方式实现远程调用
* 3.openfeign接口地址需要和远程调用服务的地址一致
*/
@GetMapping("/member/get/{id}")
Result getMemberById(@PathVariable("id") Long id);
}
6.创建MemberConsumerFeignController.java
@RestController
@RequiredArgsConstructor
public class MemberConsumerFeignController {
//装配MemberFeignService
private final MemberFeignService memberFeignService;
@GetMapping(value = "/member/consumer/openfeign/get/{id}")
public Result getMemberById(@PathVariable("id") Long id) {
return memberFeignService.getMemberById(id);
}
}
7.启动测试
openfeign默认轮询的方式实现负载均衡
2.指定url地址,不经过Ribbon的服务选择,直接请求服务
@Component
/**
* 指定远程调用url,用于固定访问某个服务不经过注册中心做服务的发现
* value 和 name 的作用一样,如果没有配置url那么配置的值将作为服务名称,用于服务发现。反之只是一个名称。
*/
@FeignClient(name = "member",url = "192.168.79.1:10001")
public interface MemberFeignService {
//定义方法-远程调用接口
@GetMapping("/member/get/{id}")
Result getMemberById(@PathVariable("id") Long id);
}
3.动态url地址,不经过Ribbon的服务选择,直接请求服务
/**
* 1.指定远程调用url,用于固定访问某个服务不经过注册中心做服务的发现
* 2.value 和 name 的作用一样,如果没有配置url那么配置的值将作为服务名称,用于服务发现。反之只是一个名称。
* 3.contextId 当name/value相同时,指定不同的id来做区别
* 也可以通过配置spring.main.allow-bean-definition-overriding=true来解决名称冲突的问题
* 4.${member-provider.requesturl:} 从yml配置文件中读取
*/
@FeignClient(name = "member",url = "${member-provider.requesturl:}",contextId = "dynamicUrl")
@Component
public interface MemberFeignDynamicUrlService {
@GetMapping("/member/get/{id}")
Result getMemberById(@PathVariable("id") Long id);
}
3.OpenFeign-日志配置
1.基本介绍
-
说明: Feign 提供了日志打印功能,可以通过配置来调整日志级别,从而对 Feign 接口的 调用情况进行监控和输出
-
日志级别
NONE∶默认的,不显示任何日志
BASIC∶仅记录请求方法、URL、响应状态码及执行时间;HEADERS∶除了 BASIC中定义的信息之外,还有请求和响应的头信息;
FULL∶除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。
2.配置日志-应用实例
1.创建配置类
//@Configuration, OpenFeign全局日志配置
@Configuration
public class OpenFeignConfig {
/**
* 指定日志级别
* @return
*/
@Bean
public Logger.Level logLevel(){
return Logger.Level.FULL;
}
}
2.修改yml文件,指定openfeign日志级别
logging:
# openfeign接口远程调用过程打印信息 级别-Debug
level:
com.llp.springcloud.service.MemberFeignService: debug
3.启动测试
[MemberFeignService#getMemberById]
2022-09-08 21:28:18.980 DEBUG 25628 --- [p-nio-80-exec-1] c.l.s.service.MemberFeignService : [MemberFeignService#getMemberById] {"code":"200","msg":"查询会员成功member-service-provider-10000","data":{"id":1,"name":"smith","pwd":"202cb962ac59075b964b07152d234b70","mobile":"123456789000","email":"smith@sohu.com","gender":1}}
2022-09-08 21:28:18.980 DEBUG 25628 --- [p-nio-80-exec-1] c.l.s.service.MemberFeignService : [MemberFeignService#getMemberById] <--- END HTTP (202-byte body)
4.OpenFeign-超时时间配置
1.先看一个问题
1.src\main\java\com\llp\springcloud\controller\MemberController.java新增一个测试超时的方法
/**
* 测试openfeign超时,默认1秒
* @return
*/
@GetMapping(value = "/member/timeout")
public Result timeout() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return Result.success();
}
2.修改src\main\java\com\llp\springcloud\service\MemberFeignService.java
/**
* 测试openfeign超时
* @return
*/
@GetMapping(value = "/member/timeout")
Result timeout();
3.member-service-provider-10000、member-service-provider-10002两个服务端添加对应的模拟超时的方法
/**
* 测试openfeign超时,默认1秒
* @return
*/
@GetMapping(value = "/member/timeout")
public Result timeout() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return Result.success();
}
4.访问测试
openfeign默认超时时间为1秒,即调用得到响应的时间超出1秒则会超时抛出异常
2.设置超时时间
1.设置Ribbon的超时时间(不推荐)
设置很简单,在配置文件中添加如下设置:
ribbon:
#1. 设置feign客户端超时时间(openfeign默认支持ribbon)
#2. ReadTimeout: 5000: 建立连接从服务提供方获取可用资源的所用的全部时间
#3. 时间单位是毫秒
ReadTimeout: 5000
#两端连接所用时间
ConnectionTimeout: 5000
2.设置openFeign的超时时间(推荐)
openFeign设置超时时间非常简单,只需要在配置文件中配置,如下:
feign:
client:
config:
## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
default:
connectTimeout: 5000
readTimeout: 5000
再次测试
default设置的是全局超时时间,对所有的openFeign接口服务都生效
但是正常的业务逻辑中可能涉及到多个openFeign接口的调用,如下图:
那么上面配置的全局超时时间能不能通过呢?很显然是serviceA、serviceB能够成功调用,但是serviceC并不能成功执行,肯定报超时。
此时我们可以给serviceC这个服务单独配置一个超时时间,配置如下:
feign:
client:
config:
## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
default:
connectTimeout: 5000
readTimeout: 5000
## 为serviceC这个服务单独配置超时时间
serviceC:
connectTimeout: 30000
readTimeout: 30000
这样A、B两个服务的超时时间就是50s,而C服务的超时时间就是30s了
5.OpenFeign-指定公共请求参数
1.创建FeignRequestHeaderInterceptor.java
@Slf4j
@RequiredArgsConstructor
public class FeignRequestHeaderInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
try {
Date currentTime = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.ENGLISH);
String date = simpleDateFormat.format(currentTime);
requestTemplate.header("Date", date);
requestTemplate.header("Address", "00000");
//requestTemplate.body();
} catch (Exception e) {
log.error("会话Authorization异常", e);
}
}
}
2.在openfeign接口中指定配置类
@Component
//configuration是配置Feign配置类,在配置类中可以自定义Feign的Encoder、Decoder、LogLevel、Contract等。
@FeignClient(value = "MEMBER-SERVICE-PROVIDER",configuration = {FeignRequestHeaderInterceptor.class})
public interface MemberFeignService {
//定义方法-远程调用接口
/**
* 1. 远程调用的方式是get
* 2. 远程调用的url http://MEMBER-SERVICE-PROVIDER/member/get/{id}
* 3. MEMBER-SERVICE-PROVIDER 就是服务提供方在Eureka Server 注册的服务
* 4. openfeign 会根据负载均衡来决定调用10000/10002-默认是轮询
* 5. 因为openfeign 好处是支持了springmvc注解 + 接口解耦
* <p>
* openfeign是怎么样去远程调用的呢?
* 1.注册中心通过MEMBER-SERVICE-PROVIDER服务注册名从注册中心去获取请求地址
* 192.168.79.1:member-service-provider:10002 , 192.168.79.1:member-service-provider:10001
* 2.通过springmvc注解 + 接口的方式实现远程调用
* 3.openfeign接口地址需要和远程调用服务的地址一致
*/
@GetMapping("/member/get/{id}")
Result getMemberById(@PathVariable("id") Long id);
/**
* 测试openfeign超时
* @return
*/
@GetMapping(value = "/member/timeout")
Result timeout();
}
6.OpenFeign发送Https请求如何忽略SSL证书认证
我们在使用opefeign框架去发送Https请求调用服务器接口时,如果服务器没有证书或者证书过期,但还是要https去调用,我们可以直接绕过SSL证书认证,否则就可能出现SSLHandshakeException异常情况,那么我们该如何使OpenFeign绕过SSL验证呢?
FeginClient作为一个http请求工具,用来调用第三方接口,但是由于第三方接口常常是https开头,导致在调用的时候,触发SSL安全认证,这时候也就可以使用绕过认证的方法。
这里我们就以Springcloud项目整合OpenFeign框架为例,我们只需将Feign的配置类修改如下即可:
@Configuration
public class FeignConfiguration {
@Bean
public CachingSpringLoadBalancerFactory cachingFactory(SpringClientFactory clientFactory) {
return new CachingSpringLoadBalancerFactory(clientFactory);
}
@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) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
//如果这里后续报空指针,就return new X509Certificate[0]
return null;
}
};
ctx.init(null, new TrustManager[]{tm}, null);
return new LoadBalancerFeignClient(new Client.Default(ctx.getSocketFactory(),
(hostname, session) -> true),
cachingFactory, clientFactory);
}
}
更多细节可以参考:OpenFeign介绍和使用注意
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/81211.html