• 基于Feign接口的全链路拦截器


    1、前言

            单体应用时,我们经常会把一些共享数据,比如登录信息等放在session里面,当然也可以放在ThreadLocal里面。随着业务复杂度的提高,分布式应用越来越主流。单机的存储的思想已经不适用了,共享session应运而生,比如nosql、session复制等技术方案。

            分布式架构中SpringCloud使用尤为广泛。如果想通过Feign接口的调用隐式的传递一些参数,比如用户ID、名称,接口的验签等,我们应该怎么实现呢。Feign为我们提供全链路Request拦截器:feign.RequestInterceptor

            今天通过传递用户名到feign服务端,来使用 RequestInterceptor 来实现, 同时对比一下web的拦截器 HandlerInterceptor 的区别。

    2、实现思路

            调用端和服务端是两个不同的服务,ThreadLocal的方式不能横跨里两个服务。feign.RequestInterceptor 接口可以将请求转发到Feign接口对应的服务中。

    • 创建web拦截器,模拟登录请求,将用户名存放到ThreadLocal中。
    •  调用Feign接口之前,会调用 feign.RequestInterceptor接口,将ThreadLocal中信息存放到Feign接口的Request中。
    •  通过Feign接口的Request对象就可以获取用户名

    3、最佳实践-调用端

            3.1 调用端-web拦截器模拟登录

    1. public class IWebRequestInterceptor implements AsyncHandlerInterceptor {
    2. @Override
    3. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    4. // 模拟登录
    5. Map stringStringMap = new HashMap<>();
    6. stringStringMap.put("username", "admin");
    7. RequestHolder.set(stringStringMap);
    8. return AsyncHandlerInterceptor.super.preHandle(request, response, handler);
    9. }
    10. @Override
    11. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    12. RequestHolder.remove();
    13. AsyncHandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    14. }
    15. }

            3.2 调用端-RequestHolder

    1. public class RequestHolder {
    2. private RequestHolder() {}
    3. private static final ThreadLocal> THREAD_LOCAL = new ThreadLocal>();
    4. public static void set(Map map){
    5. THREAD_LOCAL.set(map);
    6. }
    7. public static Map get(){
    8. return THREAD_LOCAL.get() == null ? new HashMap() : THREAD_LOCAL.get();
    9. }
    10. public static void remove() {
    11. THREAD_LOCAL.remove();
    12. }
    13. }

            3.3 调用端-调用Feign之前的feign.RequestInterceptor

    1. @Configuration
    2. public class IRequestInterceptor implements RequestInterceptor {
    3. @Override
    4. public void apply(RequestTemplate template) {
    5. Map stringStringMap = RequestHolder.get();
    6. if (stringStringMap != null) {
    7. for (Map.Entry entry : stringStringMap.entrySet()){
    8. template.header(entry.getKey(), entry.getValue());
    9. }
    10. }
    11. }
    12. }

            3.4 调用端-拦截器的配置

    1. @Configuration
    2. public class WebConfig implements WebMvcConfigurer {
    3. @Override
    4. public void addInterceptors(InterceptorRegistry registry) {
    5. registry.addInterceptor(new IWebRequestInterceptor()).addPathPatterns("/**");
    6. WebMvcConfigurer.super.addInterceptors(registry);
    7. }
    8. }

            调用端的实现,已经实现了用户名传递到服务端。

    4、测试结果

    服务端结果获取

    结果打印:

    4、最佳实践-服务端

            服务端本身需要配置就可以从Request中获取Header中的用户名。但是服务端也可能调用其他服务端,资深作为调用端。所以服务端也应该要有和调用端一样的配置,最终把用户名保存再自己的服务的ThreadLocal里面。既可以从ThreadLocal里面去也可以从Request里面取。

            配置同调用端。web拦截的的配置略有差异,需要从Request中湖区参数,放到服务端的ThreadLocal中。

    1. public class IWebRequestInterceptor implements AsyncHandlerInterceptor {
    2. @Override
    3. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    4. Map stringStringMap = new HashMap<>();
    5. String username = request.getHeader("username");
    6. stringStringMap.put("username", username);
    7. RequestHolder.set(stringStringMap);
    8. return AsyncHandlerInterceptor.super.preHandle(request, response, handler);
    9. }
    10. }

    5、HandlerInterceptor 和 RequestInterceptor 的区别

    • HandlerInterceptor是 org.springframework.web.servlet(spring-webmvc)包下,而RequestInterceptor 是feign(feign-core)包下。
    • HandlerInterceptor拦截器是需要配置拦截的请求,RequestInterceptor 不用,只需要交给Spring管理即可。
    • HandlerInterceptor优先与RequestInterceptor 执行,RequestInterceptor 在调用Feign接口之前执行
  • 相关阅读:
    [附源码]计算机毕业设计JAVA化妆品销售管理系统
    instant.page:可以提生网页加载速度50%的JavaScript脚本
    C++中使用 min()函数/max()函数进行多数比较
    【Spring(六)】使用篇:AOP在开发中的使用
    【英语:语法基础】C1.日常对话-自我介绍
    中等array and sorting :count and say
    30天Python入门(第十七天:深入了解Python中的异常处理)
    Fiddler弱网测试
    家电生产线数控机床上下料长臂机器人组设计
    就推荐 4 个 yyds 的开源项目
  • 原文地址:https://blog.csdn.net/static_coder/article/details/127888987