Spring Cloud在Zull路由时Token和相关信息传递解决方案

  • Post author:
  • Post category:其他




Spring Cloud在Zull路由时Token和相关信息传递解决方案

Spring Cloud在采用Zull实现路由分发,可以采用Feign实现快速微服务调用,极大解放微服务之间负责的调用关系。

Zull微服务架构示意图



微服务之间的Token传递问题

微服务之间Token传递问题



微服务之间Token和其他请求参数传递问题



实现feign.RequestInterceptor解决请求参数传递问题

@Slf4j
public class FeignBasicAuthRequestInterceptor implements RequestInterceptor {
	
    public static final String KEY_SERVER_TOKEN = "serverToken";
	public static final String KEY_SERVICE_NAME = "serviceName";
	
    private static ServerConfig serverConfig;

    @Lazy
    @Autowired
    public void setServerConfig(ServerConfig serverConfig) {
    	FeignBasicAuthRequestInterceptor.serverConfig = serverConfig;
    }
	
	@Override
	public void apply(RequestTemplate template) {
		template.header(KEY_SERVICE_NAME, serverConfig.getThisName());
		// UserUtils 从ThreadLocal中取已登路用户对象
		JSONObject claims = JSON.parseObject(JSON.toJSONString(UserUtils.getUser()));
		if (claims == null){
			// 线程环境没有用户信息时,尝试从请求上下文获取
			ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
			log.warn("---No user information---");
			if (attributes == null) return;
			Object userStr = attributes.getAttribute(UserUtils.CURRENT_USER_KEY, SCOPE_REQUEST);
			if (userStr != null && userStr instanceof String){
				claims = JSON.parseObject(userStr.toString());
			}
		}
		log.debug("Add server token:{}", claims == null ? "NULL" : claims.toJSONString());
		// 生成请求头参数
		String serverToken = null;
		try {
			serverToken = JwtUtils.generateJwt(
					serverConfig.getThisId(), serverConfig.getThisExpire(), serverConfig.getThisSecret(), claims);
		} catch (Exception e) {
			log.error("JWT 生成服务token异常:{}", e);
			throw new BizException(ErrorInfoEnum.ERROR_SERVICE_EXCEPTION);
		}
		log.debug("serviceName:{}, serverToken:{}", serverConfig.getThisName(), serverToken);
		template.header(KEY_SERVER_TOKEN, serverToken);
	}

}



重写HystrixConcurrencyStrategy解决跨线程传参数传递问题

如上图所示,如果Hystrix创建了新线程,那么ThreadLocal是无效的,所以需要将信息传递到新线程,这个工作可以通过重写HystrixConcurrencyStrategy(Hystrix并发策略)实现,代码如下。

@Component
public class FeignHystrixConcurrencyStrategyIntellif extends HystrixConcurrencyStrategy {
    private static final Logger log = LoggerFactory.getLogger(FeignHystrixConcurrencyStrategyIntellif.class);
    private HystrixConcurrencyStrategy delegate;

    public FeignHystrixConcurrencyStrategyIntellif() {
        try {
            this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
            if (this.delegate instanceof FeignHystrixConcurrencyStrategyIntellif) {
                // Welcome to singleton hell...
                return;
            }
            HystrixCommandExecutionHook commandExecutionHook =
                    HystrixPlugins.getInstance().getCommandExecutionHook();
            HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
            HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();
            HystrixPropertiesStrategy propertiesStrategy =
                    HystrixPlugins.getInstance().getPropertiesStrategy();
            this.logCurrentStateOfHystrixPlugins(eventNotifier, metricsPublisher, propertiesStrategy);
            HystrixPlugins.reset();
            HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
            HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);
            HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
            HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
            HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
        } catch (Exception e) {
            log.error("Failed to register Sleuth Hystrix Concurrency Strategy", e);
        }
    }

    private void logCurrentStateOfHystrixPlugins(HystrixEventNotifier eventNotifier,
                                                 HystrixMetricsPublisher metricsPublisher, HystrixPropertiesStrategy propertiesStrategy) {
        if (log.isDebugEnabled()) {
            log.debug("Current Hystrix plugins configuration is [" + "concurrencyStrategy ["
                    + this.delegate + "]," + "eventNotifier [" + eventNotifier + "]," + "metricPublisher ["
                    + metricsPublisher + "]," + "propertiesStrategy [" + propertiesStrategy + "]," + "]");
            log.debug("Registering Sleuth Hystrix Concurrency Strategy.");
        }
    }

    @Override
    public <T> Callable<T> wrapCallable(Callable<T> callable) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 添加当前线程用户信息到请求属性(从Thread Local获取数据,写到包装对象,在调用时再设置到请求上下文)
        requestAttributes.setAttribute(UserUtils.CURRENT_USER_KEY, JSON.toJSONString(UserUtils.getUser()), SCOPE_REQUEST);
        return new WrappedCallable<>(callable, requestAttributes);
    }

    @Override
    public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
                                            HystrixProperty<Integer> corePoolSize, HystrixProperty<Integer> maximumPoolSize,
                                            HystrixProperty<Integer> keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        return this.delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime,
                unit, workQueue);
    }

    @Override
    public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
                                            HystrixThreadPoolProperties threadPoolProperties) {
        return this.delegate.getThreadPool(threadPoolKey, threadPoolProperties);
    }

    @Override
    public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
        return this.delegate.getBlockingQueue(maxQueueSize);
    }

    @Override
    public <T> HystrixRequestVariable<T> getRequestVariable(HystrixRequestVariableLifecycle<T> rv) {
        return this.delegate.getRequestVariable(rv);
    }

    static class WrappedCallable<T> implements Callable<T> {
        private final Callable<T> target;
        private final RequestAttributes requestAttributes;

        public WrappedCallable(Callable<T> target, RequestAttributes requestAttributes) {
            this.target = target;
            this.requestAttributes = requestAttributes;
        }

        @Override
        public T call() throws Exception {
            try {
                RequestContextHolder.setRequestAttributes(requestAttributes);
                return target.call();
            } finally {
                RequestContextHolder.resetRequestAttributes();
            }
        }
    }
}

参考:https://www.codeleading.com/article/9636193523/



版权声明:本文为yin138原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。