1. 创建一个配置文件
@Configuration
public class TenantFeignConfig {
    @Bean
    public RequestInterceptor tenantIdInterceptor() {
        return template -> {
            // 从当前线程上下文获取租户ID(需自行实现租户上下文管理)
            String tenantId = AuthUtil.getTenantId();
            if (Func.isNotBlank(tenantId)) {
                template.header("Blade-TenantId", tenantId);
            }
        };
    }
}2. Feign Client 接口引入配置文件
@FeignClient(
        value = BaseAppConstant.APPLICATION_BASE_NAME,
        fallback = IBaseChannelClientFallback.class,
        configuration = TenantFeignConfig.class
)
public interface IBaseChannelClient {
3. Client 实现类
@RestController
@RequiredArgsConstructor
public class BaseChannelClient implements IBaseChannelClient {
    private final IBaseChannelService baseChannelService;
    private final BladeContext bladeContext;
    @Override
    public R<BaseChannel> getChannel(Long id) {
        String tenantId = bladeContext.getTenantId(); // 获取租户Id
        try {
            DynamicDataSourceContextHolder.push(tenantId); // 切换数据源(如不需要可以去掉 try{...}finally{...} )
            return R.data(
                    TenantUtil.use(tenantId, () -> baseChannelService.getById(id)) // 线程注入租户Id
            );
        } finally {
            DynamicDataSourceContextHolder.poll();
        }
    }
}希望官方可以封装上述功能到tool中
这个逻辑无法写到tool里全局生效,需要手动处理
我后来优化了一下,代码更新到自己公司代码库了。可以参考一下,实现租户远程调用确实有很大的便利。
1. @TenantFeign
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface TenantFeign {
    /**
     * 是否开启租户动态数据源
     *
     * @return
     */
    boolean tenantDS() default false;
}2. FeignTenantAspect
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class FeignTenantAspect {
    private final BladeContext bladeContext;
    @Pointcut("@within(org.springblade.core.tenant.annotation.TenantFeign) || " +
            "@annotation(org.springblade.core.tenant.annotation.TenantFeign)")
    public void feignTenantPointcut() {
    }
    @Around("feignTenantPointcut()")
    public Object handleFeignTenant(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String tenantId = bladeContext.getTenantId();
        TenantFeign tenantFeign = AnnotationUtils.findAnnotation(method, TenantFeign.class);
        if (tenantFeign == null) {
            tenantFeign = AnnotationUtils.findAnnotation(joinPoint.getTarget().getClass(), TenantFeign.class);
        }
        if (tenantFeign == null || Func.isBlank(tenantId)) {
            return joinPoint.proceed();
        }
        boolean tenantDS = tenantFeign.tenantDS();
        try {
            if (tenantDS) {// 切换租户数据源
                DynamicDataSourceContextHolder.push(tenantId);
            }
            return TenantUtil.use(tenantId, () -> {
                try {
                    return joinPoint.proceed();
                } catch (Throwable e) {
                    throw new RuntimeException(e);
                }
            });
        } finally {
            if (tenantDS) {
                DynamicDataSourceContextHolder.poll();
            }
        }
    }
}3. 实现方式
@TenantFeign(tenantDS = true)  // tenantDS=true 开启租户多数据源,默认false, 只传递租户Id
@Hidden
@RestController
@RequiredArgsConstructor
public class BaseBrandClient implements IBaseBrandClient {
    private final IBaseBrandService baseBrandService;
    @Override
    public R<BaseBrand> getBaseBrand(Long id) {
        // 实现方发不需要改变
        return R.data(this.baseBrandService.getById(id));
    }
    @Override
    public R<Collection<BaseBrand>> listBaseBrand() {
        return R.data(this.baseBrandService.list(Wrappers.<BaseBrand>query().lambda()));
    }
}
 
后续我们评估优化下这个功能
4.7.0版本开始已支持