我们在开发过程中,常有这样的需求,要将当前的微服务参数传递到下一个微服务,比如userId或者token之类,如果我们使用SpringCloud,把参数放到Header里就可以轻松实现了参数的传递。

下面是一个利用Feign的RequestInterceptor实现的例子

 

这里使用ThreadLocal来保持参数,这样在当前的环境中就可以随时使用了

package app.gateway.threadLocal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;

public class PassParameters {

        private static final Logger log = LoggerFactory.getLogger(PassParameters.class);

        private static final ThreadLocal localParameters = new ThreadLocal();

        public static <T> T get(){
            T t = (T) localParameters.get();
            log.info("ThreadID:{}, threadLocal {}", Thread.currentThread().getId(), JSON.toJSONString(t));
            return t;
        }

        public static <T> void set(T t){
            log.info("ThreadID:{}, threadLocal set {}", Thread.currentThread().getId(), JSON.toJSONString(t));
            localParameters.set(t);
        }
    }

设计一个切面,这里是gateway的切面,存放相关的参数,我这里放到map中,页可以自定义一个对象,放对象中

package app.gateway.aop;


import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import app.gateway.threadLocal.PassParameters;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
 
/**
 * @author hsn
 */
@Aspect
@Component
public class ApiRequestAspect {
    private static Logger logger = LoggerFactory.getLogger(ApiRequestAspect.class);
 

    @Pointcut("execution (* app.gateway.controller.ApiController.*(..)) ")
    private void anyMethod() {
    }
 
    /**
     * 方法调用之前调用
     */
    @Before("anyMethod()")
    public void doBefore(){
        logger.info("开始处理请求信息!");
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getRequest();
 
        Map<String,String> map = new HashMap<>();
        String username = request.getParameter("username");
        String token = request.getParameter("token");
        
        map.put("username", username);
        map.put("token", token);
        
        //将map放到threadLocal中
        PassParameters.set(map);
    }
 
    /**
     * 方法之后调用
     */
    @AfterReturning(pointcut = "anyMethod()")
    public void  doAfterReturning(){
        
    }
    
}

自定义 RequestInterceptor

 

package app.gateway.config;


import feign.Feign;
import feign.RequestInterceptor;
import feign.RequestTemplate;

import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;

import app.gateway.threadLocal.PassParameters;
 
@Configuration
@ConditionalOnClass(Feign.class)
public class DefaultFeignConfig implements RequestInterceptor {
 
    @Value("${spring.application.name}")
    private String appName;
 
    @Override
    public void apply(RequestTemplate requestTemplate)
    {
        Map<String,String> map = PassParameters.get();
        
        String username = map.get("username");
        if(StringUtils.isNotEmpty(username)){
            requestTemplate.header("username", username);
        }
        String token = map.get("token");
        if(StringUtils.isNotEmpty(token)){
            requestTemplate.header("token", token);
        }
        
    }
 
}
 

 

在后端的service,用切面取出保存在head中的参数

package app.service.aop;


import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import app.service.threadLocal.PassParameters;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
 
/**
 * @author hsn
 */
@Aspect
@Component
public class ApiRequestAspect {
    private static Logger logger = LoggerFactory.getLogger(ApiRequestAspect.class);
 

    @Pointcut("execution (* app.service.controller.AppServiceController.*(..)) ")
    private void anyMethod() {
    }
 
    /**
     * 方法调用之前调用
     */
    @Before(value= "anyMethod()")
    public void doBefore(JoinPoint jp){
        logger.info("开始处理请求信息!");
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getRequest();
 
        Map<String,String> map = new HashMap<>();
        String username =  request.getHeader("username");
        String token = request.getHeader("token");
        
        map.put("username", username);
        map.put("token", token);
        
        //将map放到threadLocal中
        PassParameters.set(map);
    }
 
    /**
     * 方法之后调用
     */
    @AfterReturning(pointcut = "anyMethod()")
    public void  doAfterReturning(){
        
    }
    
}

 

详细代码请参考:https://github.com/hsn999/springCloud/tree/master/springCloud-feign-pass-parameters

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐