SpringCloudはFeignによるサービス間呼び出しスレッド変数転送を実現

18550 ワード

前言
  プロジェクトを開発する過程で、登録された情報を一つのサービスから別のサービスに伝達するなど、サービスにまたがっていくつかのデータを伝送する必要があることが多い.この場合、既存のコードをできるだけ少なく動かす必要があり、プログラミングのパッケージ思想をより体現している.  SpringCloudはdubboのようにサービス間呼び出しの際に自身のスレッド変数で転送されるわけではないが、SpringCloudはそれ自体のメカニズムで実現をサポートできるに違いないという考えから、このブログがあった.
実現構想.
  • スレッド間で
  • を共有するためのThreadLoad変数を準備する
  • 各サービスは、すべてのFeign呼び出しをフィルタリングし、要求ヘッダからユーザ情報を取得し、ThreadLocal変数の
  • が存在する.
  • 各サービスは、FeignClientを使用して他のサービスを呼び出す際に、まずThreadLocal変数からユーザ情報を取り出し、Feginのrequest要求ヘッダに
  • を置く.
  • は1つの注釈をカプセル化し、起動クラスに
  • をマークすることができる.
    キーコード
    1、ThreadLocalツール類
    public class UserContext {
    	//         ,     ,         
        private static ThreadLocal<User> userInfo = new ThreadLocal<User>();
        //         request       
        public static String KEY_USER_IN_HTTP_HEADER = "X-AUTO-FP-USER";
    
        public UserContext() {
        }
    
        public static User getUser(){
            return (User)user.get();
        }
    
        public static void setUser(User user){
            user.set(user);
        }
    }
    

    2、ユーザー情報エンティティクラス
    /**
     * @author    
     * @DESCRIPTION       
     * @create 2019/3/28
     */
    @Data
    public class User {
        /**
         *   id
         */
        private String id;
        /**
         *     
         */
        private String userCode;
        /**
         *     
         */
        private String userName;
        /**
         *   id
         */
        private String companyId;
        /**
         * token
         */
        private String token;
        /**
         *     id
         */
        private String roleId;
        /**
         *
         * qq      
         */
        private String qqOpenId;
        /**
         *
         *         
         */
        private String weChatOpenId;
        /**
         *
         *          
         */
        private String wxPlantForm;
    }
    

    3、FeignClientブロッキング
    public class TransmitUserFeighClientIntercepter implements RequestInterceptor {
    
        private static final Logger log = LoggerFactory.getLogger(TransmitUserFeighClientIntercepter.class);
        public TransmitUserFeighClientIntercepter() {
        }
    
        @Override
        public void apply(RequestTemplate requestTemplate) {
            //         user  ,  Feign     
            User user = UserContext.getUser();
            if (user != null) {
                try {
                    String userJson = JSON.toJSONString(user);
                    requestTemplate.header("KEY_USER_IN_HTTP_HEADER",new String[]{URLDecoder.decode(userJson,"UTF-8")});
                } catch (UnsupportedEncodingException e) {
                    log.error("        ",e);
                }
            }
        }
    }
    

    4、Filterフィルタ
    public class TransmitUserFilter implements Filter {
    
        private static final Logger log = LoggerFactory.getLogger(TransmitUserFeighClientIntercepter.class);
        public TransmitUserFilter() {
        }
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
           this.initUserInfo((HttpServletRequest)request);
           chain.doFilter(request,response);
        }
    
        private void initUserInfo(HttpServletRequest request){
            String userJson = request.getHeader("KEY_USER_IN_HTTP_HEADER");
            if (StringUtils.isNotBlank(userJson)) {
                try {
                    userJson = URLDecoder.decode(userJson,"UTF-8");
                    User userInfo = (User) JSON.parseObject(userJson,UserInfo.class);
                    //           
                    UserContext.setUser(user);
                } catch (UnsupportedEncodingException e) {
                   log.error("init userInfo error",e);
                }
            }
        }
    
        @Override
        public void destroy() {
        }
    }
    

    5、カスタム注釈
    @Documented
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Import({EnableUserTransmitterAutoConfiguration.class})
    public @interface EnableUserTransmitter {
    }
    

    6、カスタム注釈実装クラス
    @Configuration
    public class EnableUserTransmitterAutoConfiguration {
    
        public EnableUserTransmitterAutoConfiguration() {
        }
    
        @Bean
        public TransmitUserFeighClientIntercepter transmitUser2FeighHttpHeader(){
           return new TransmitUserFeighClientIntercepter();
        }
    
        @Bean
        public TransmitUserFilter transmitUserFromHttpHeader(){
            return new TransmitUserFilter();
        }
    }
    

    7、起動クラスにカスタム注釈をマークする