1. 导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2. 开启 openFeign
配置类或者启动类上添加注解,自动扫描已经定义好的 FignClient
@EnableFeignClients({"package1", "package2"})
3. 全局处理
异常、编解码、重试、鉴权等。
@Configuration
@ConditionalOnClass({EnableFeignClients.class})
public class FeignConfiguration {
public FeignConfiguration() {
}
@Bean
public FeignBasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new FeignBasicAuthRequestInterceptor();
}
@Bean
public FeignExceptionAspect feignExceptionAspect() {
return new FeignExceptionAspect();
}
@Bean
public Retryer feignRetryer() {
return Retryer.NEVER_RETRY;
}
@Bean
public Decoder feignDecoder() {
final MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
simpleModule.addDeserializer(BigDecimal.class, BigDecimalJsonDeserializer.instance);
simpleModule.addSerializer(BigDecimal.class, BigDecimal2Serializer.instance);
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(Date.class, new DateSerializer(false, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addDeserializer(Date.class, new DateDeserializer());
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
objectMapper.registerModule(javaTimeModule);
objectMapper.registerModule(simpleModule);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
List<MediaType> fastMediaTypes = new ArrayList();
fastMediaTypes.add(MediaType.ALL);
jackson2HttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);
jackson2HttpMessageConverter.setObjectMapper(objectMapper);
ObjectFactory<HttpMessageConverters> objectFactory = new ObjectFactory<HttpMessageConverters>() {
public HttpMessageConverters getObject() throws BeansException {
return new HttpMessageConverters(new HttpMessageConverter[]{jackson2HttpMessageConverter});
}
};
return new ResponseEntityDecoder(new SpringDecoder(objectFactory));
}
}
4. 关键代码
鉴权:
public class FeignBasicAuthRequestInterceptor implements RequestInterceptor {
public FeignBasicAuthRequestInterceptor() {
}
public void apply(RequestTemplate template) {
// 1. 通过设置一个永久的 token 来鉴权
template.header("access-token", "xxxxx");
// 2. 也可以获取 requestAttributes 放入 header中,当然这个是大家提前约定好
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
Enumeration<String> reqAttrbuteNames = request.getAttributeNames();
if (reqAttrbuteNames != null) {
while(reqAttrbuteNames.hasMoreElements()) {
String attrName = (String)reqAttrbuteNames.nextElement();
// isAuthorizationed 是约定好的自定义头,方便内部调用
if ("isAuthorizationed".equalsIgnoreCase(attrName)) {
Map<String, String> requestHeaderMap = (Map)request.getAttribute(attrName);
Iterator var7 = requestHeaderMap.entrySet().iterator();
while(var7.hasNext()) {
Entry<String, String> entry = (Entry)var7.next();
template.header((String)entry.getKey(), new String[]{(String)entry.getValue()});
}
return;
}
}
}
}
}
}
异常处理:
@Aspect
public class FeignExceptionAspect {
public FeignExceptionAspect() {
}
@Pointcut("@within(org.springframework.cloud.openfeign.FeignClient)")
public void feignClientPointCut() {
}
@Around("feignClientPointCut()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object object = proceedingJoinPoint.proceed();
if (object == null) {
throw new BusinessException(ResponseCode.FAILED.getCode(), "服务间调用异常,请稍后重试!");
} else if (object instanceof HttpResult) {
HttpResult<?> httpResult = (HttpResult)object;
if (Objects.equals(ResponseCode.SUCCESS.getCode(), httpResult .getCode()) && httpResult .isSuccess()) {
return object;
} else {
throw new BusinessException(ResponseCode.FAILED.getCode(), httpResult .getMsg());
}
} else {
return object;
}
}
}
注意:feign 异常处理中并没有捕获被调用方抛出的异常,通常被调用方都会做框架级别全局异常处理封装装成了HttpResult,但是调用方超时异常还是需要处理:
try {
Object object = proceedingJoinPoint.proceed();
} catch(Exception e) {
// feign.RetryableException: timeout executing POST
}
这样做的好处是,被调用接口既可以被直接调用,也可以被远程内部调用。
5. 使用
可以通过微服务的注册中新和 @EnableDiscoveryClient 注解来自动发现服务:
@FeignClient(value = "userCenter", path = "/userCenter")
public interface InternetusercenterServiceInterface {
/**
* 根据ID查询用户信息
*/
@RequestMapping(value = "/userCenter/getUserInfoById", method = RequestMethod.GET)
HttpResult<UserInfoVO> getUserInfoById(@RequestParam Long id);
}
本文结束,做任何事情先把整体后局部, 使用 openFeign 步骤是什么,然后每一步去实现他就可以了。
如果觉得还不错的话,关注、分享、在看(关注不失联~), 原创不易,且看且珍惜~


本文详细介绍了如何在Spring Cloud项目中集成和配置OpenFeign,包括引入依赖、开启服务、全局异常处理和自定义配置。在异常处理部分,展示了如何定制Feign的异常拦截器,以及如何优雅地处理服务间的调用异常。此外,还提供了使用FeignClient进行服务调用的示例。通过这些步骤,你可以更好地理解和应用OpenFeign进行微服务之间的通信。
6911

被折叠的 条评论
为什么被折叠?



