Spring Cloud在采用Zull实现路由分发,可以采用Feign实现快速微服务调用,极大解放微服务之间负责的调用关系。
@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);
}
}
如上图所示,如果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/