<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${openfeign.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-io</artifactId>
<groupId>commons-io</groupId>
</exclusion>
</exclusions>
</dependency>
@FeignClient(name = "user-service", url = "${lq.getewayIp}/api/user-service", configuration = FeignRequestConfiguration.class, fallback = UserFeignFallBack.class)
public interface UserFeign {
/**
* 获取登录信息
*/
@GetMapping("/user/getLoginInfo")
R getLoginInfo(@RequestParam(name = "token") String token);
/**
* 获取当前登录人的信息
*/
@GetMapping("/user/getCurrentUserInfo")
R getCurrentUserInfo();
}
@FeignClient(name = "user-service", url = "${lq.getewayIp}/api/user-service", configuration = FeignRequestConfiguration.class, fallback = UserFeignFallBack.class)
## 解释
//@FeignClient:这是Feign客户端的注解。
//name = "user-service":定义Feign客户端的名称,这个名称通常与服务发现(例如nacos)中的服务名称匹配。
//url = "${lq.getewayIp}/api/user?service":定义Feign客户端的URL。这里使用了Spring的属性引用‘{lq.getewayIp},这意味着在运行时,lq.getewayIp`的值会被用来填充URL
//configuration = FeignRequestConfiguration.class:定义Feign客户端的配置类。你可以在这个FeignRequestConfiguration类中定义特定于这个Feign客户端的配置,例如请求/响应的序列化和反序列化、拦截器、拦截器等
//fallback = UserFeignFallBack.class:这是Feign客户端的fallback类,当调用目标服务失败时(例如由于网络问题、服务宕机等原因),Feign客户端会自动调用这个fallback类中的方法。这个类通常会处理失败的情况,例如返回默认值或执行重试策略等
## 总结
//这个注解定义了一个Feign客户端,用于与服务名为"user-service"的服务进行通信,并且提供了URL、配置和fallback等属性
定义了如何定制Feign客户端的请求
这个拦截器的目的是从原始的HTTP请求中复制所有的头部信息(除了"content-length")到Feign客户端发出的请求中。这样,当使用Feign客户端发起请求时,它可以保持与原始HTTP请求相同的头部设置
// @Configuration:这是一个Spring的注解,表示该类是一个配置类,用于定义和配置Spring Bean。
@Configuration
//这定义了一个名为FeignRequestConfiguration的类,该类实现了RequestInterceptor接口。RequestInterceptor是Feign客户端的一个接口,用于拦截和处理请求
public class FeignRequestConfiguration implements RequestInterceptor {
//这是RequestInterceptor接口中的apply方法,用于自定义请求。该方法接受一个RequestTemplate参数,这个参数代表了即将发出的请求。
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//判断如果从定时任务发起的feign请求 是无法获取到request域的 所以做过滤判断为空的时候不往feign中组装任何request域的内容
if (ObjectUtil.isNotEmpty(attributes)){
// 设置请求头 从ServletRequestAttributes中获取实际的HTTP请求
HttpServletRequest request = attributes.getRequest();
//获取HTTP请求的所有头部名称
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
//获取下一个头部名称
String name = headerNames.nextElement();
//获取该头部名称对应的值
String value = request.getHeader(name);
if (name.equals("content-length")){
continue;
}
//将获取到的头部名称和值添加到即将发出的Feign请求中
requestTemplate.header(name, value);
}
}
}
}
}
这是一个使用Spring Cloud Feign的熔断(fallback)实现类。熔断是一种在分布式系统中应对故障的方法,当某个服务调用失败或响应过慢时,熔断机制可以阻止对该服务的进一步调用,以避免整个系统的崩溃
这个UserFeignFallBack类是当Feign客户端调用目标服务失败时的备选方案。当调用失败时,它不会尝试再次调用或等待,而是直接返回一个预定义的失败响应,状态码为20004,消息为"feign熔断"。这有助于防止系统的进一步崩溃,并允许系统以一种可控制的方式失败。
public class UserFeignFallBack implements UserFeign {
@Override
public R getLoginInfo(String token) {
//当调用目标服务失败或超时时,这个熔断实现将返回这个失败响应
return R.fail(20004, "feign熔断");
}
@Override
public R getCurrentUserInfo() {
return R.fail(20004, "feign熔断");
}
}
Feign结合了Ribbon和Hystrix,提供了客户端负载均衡和故障处理能力
这些配置为Feign客户端提供了各种超时设置、负载均衡策略和故障处理机制
feign:
httpclient: //这是关于HTTP客户端的配置
connection-timer-repeat: 30000 //这表示如果连接失败,将尝试重新连接的时间间隔是30000毫秒,即30秒
###配置请求超时时间
hystrix: //Hystrix是Netflix开源的库,用于隔离、熔断和监控分布式系统的调用
command: //这指的是特定命令的配置,例如特定的Feign客户端方法。
default: // 这是默认的命令配置
execution: //这是关于Hystrix执行流的配置
isolation: // 这涉及到隔离Hystrix命令执行流的配置
thread: //这指的是使用线程来执行命令的配置
timeout: // 这指的是超时设置
enabled: true //这意味着线程超时是启用的
timeoutInMilliseconds: 60000 //这设置了线程的超时时间为60秒
调用端在启动类上添加@EnableFeignClients注解
@SpringBootApplication
@EnableFeignClients(basePackages = {"cn.com.sinosoft.*"})
public class ManagementPlanApp {
public static void main(String[] args){
SpringApplication application = new SpringApplication(ManagementPlanApp.class);
application.setApplicationStartup(new BufferingApplicationStartup(2048));
application.run(args);
System.out.println("启动成功");
}
}
具体代码中调用
//注入
@Resource
private UserFeign userFeign;
//使用
R<List<DeptVo>> specialDept = userFeign.findSpecialDeptByDeptName(deptNames);
if (specialDept.getCode() != 200) {
log.error("获取部门信息失败 -> result={}", specialDept);
throw new ServiceException("获取部门信息失败,请重新尝试");
}
List<JSONObject> deptVoList = JSONObject.parseArray(JSONObject.toJSONString(specialDept.getData()), JSONObject.class);
下面的接口不拦截token,调用feign方法放开token拦截
# 不拦截token的接口
no_filter_url: .*swagger-ui.html.*,.*/doc.html,.*/swagger-resources,.*/v2/api-docs,.*/webjars/.*,.*/favicon.ico,.*/admin.*,.*/auth/xcxLogin,.*/v3/api-docs.*,.*/getLoginInfo.*,.*/auth/xcxLogin.*,.*/file/upload.*,.*/exportData.*,.*/testReceivePosition.*,.*/testReceiveUser.*,.*/testReceiveOrg.*,.*/receiveUser.*,.*/receiveOrg.*,.*/receiveAccount.*,.*/receivePosition.*,.*/init/org.*,.*/init/org2.*,.*/init/role.*,.*/receiveItem.*,.*/test,.*/dept/findSonDept.*,.*/user/getUserId.*,.*/login.*,.*/packageZipByFolder.*,.*/downloadTemplate.*,.*/sms/message.*,.*/user/findSonUser.*,.*/user/findUser.*,.*/onlyoffice.*,.*/js.*,.*/css.*,.*/dept/findCompanyId.*,.*/editor.*,.*/viewer.*,.*/api/callback.*,.*/api/file.*,.*/dept/findProjectDept.*,.*/dept/findDept.*,.*/synchronizeUserInfo.*,.*/commentTemplatePrint.*,.*/api/before.*,.*/template.*,.*/issued.*,.*/authority.*,.*/opinion.*,.*/fileinfo.*,.*/file/download.*,.*/api/doc.*,.*/dept/findCompany.*,.*/dept/findSpecialDeptByDeptName.*,.*/user/getPersonnelUser.*,.*/user/getPersonnelAllUser.*
服务参数和请求头的传递:
服务参数和请求头的处理:
Feign 请求拦截器的工作机制: