Расширьте возможности Spring Cloud Feign для автоматического перехода на более раннюю версию

Spring Cloud

Цель автоматического перехода на более раннюю версию

Когда Spring Cloud использует притворство,Вам необходимо явно указать резервную стратегию, иначе будет выдано сообщение об ошибке.
Давайте сначала посмотрим, что требует сервис feign по умолчанию. сервис feign определяет класс factory и резервный класс

@FeignClient(value = ServiceNameConstants.UMPS_SERVICE, fallbackFactory = RemoteLogServiceFallbackFactory.class)
public interface RemoteLogService {}

Но в большинстве случаев стратегия имитации перехода на более раннюю версию будет очень простой, чтобы обеспечить идемпотентность, просто вывести журнал ошибок. Аналогично следующему коду очень неудобно разрабатывать на предприятии

@Slf4j
@Component
public class RemoteLogServiceFallbackImpl implements RemoteLogService {
	@Setter
	private Throwable cause;


	@Override
	public R<Boolean> saveLog(SysLog sysLog, String from) {
		log.error("feign 插入日志失败", cause);
		return null;
	}
}

Эффект автоматического понижения рейтинга

@FeignClient(value = ServiceNameConstants.UMPS_SERVICE)
public interface RemoteLogService {}
  • Feign Service завершает тот же вывод ошибки перехода на более раннюю версию
  • Нет необходимости определять бесполезную fallbackFactory в FeignClient.
  • FallbackFactory также не нужно регистрировать в контейнере Spring.

Изменение кода, удаление фабрики понижения версии, указанной FeignClient

Изменения кода, удаление кода, связанного с переходом на более раннюю версию

основной исходный код

  1. Внедрите наш персонализированный Feign
@Configuration
@ConditionalOnClass({HystrixCommand.class, HystrixFeign.class})
protected static class HystrixFeignConfiguration {
	@Bean
	@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
	@ConditionalOnProperty("feign.hystrix.enabled")
	public Feign.Builder feignHystrixBuilder(FeignContext feignContext) {
		return PigxHystrixFeign.builder(feignContext)
				.decode404()
				.errorDecoder(new PigxFeignErrorDecoder());
	}
}
  1. Метод PigxHystrixFeign.target — это процесс генерации прокси-класса на основе аннотации @FeignClient, обратите внимание на аннотацию
@Override
public <T> T target(Target<T> target) {
	Class<T> targetType = target.type();
	FeignClient feignClient = AnnotatedElementUtils.getMergedAnnotation(targetType, FeignClient.class);
	String factoryName = feignClient.name();
	SetterFactory setterFactoryBean = this.getOptional(factoryName, feignContext, SetterFactory.class);
	if (setterFactoryBean != null) {
		this.setterFactory(setterFactoryBean);
	}
	
	// 以下为获取降级策略代码,构建降级,这里去掉了降级非空的非空的校验
	Class<?> fallback = feignClient.fallback();
	if (fallback != void.class) {
		return targetWithFallback(factoryName, feignContext, target, this, fallback);
	}
	Class<?> fallbackFactory = feignClient.fallbackFactory();
	if (fallbackFactory != void.class) {
		return targetWithFallbackFactory(factoryName, feignContext, target, this, fallbackFactory);
	}
	return build().newInstance(target);
}
  1. Создайте фиктивный клиент для улучшения PigxHystrixInvocationHandler.
Feign build(@Nullable final FallbackFactory<?> nullableFallbackFactory) {
		super.invocationHandlerFactory((target, dispatch) ->
				new PigxHystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory));
		super.contract(new HystrixDelegatingContract(contract));
		return super.build();
	}
  1. PigxHystrixInvocationHandler.getFallback() для получения резервной политики.
	@Override
	@Nullable
	@SuppressWarnings("unchecked")
	protected Object getFallback() {
	        // 如果 @FeignClient  没有配置降级策略,使用动态代理创建一个
			if (fallbackFactory == null) {
				fallback = PigxFeignFallbackFactory.INSTANCE.create(target.type(), getExecutionException());
			} else {
			  // 如果 @FeignClient配置降级策略,使用配置的
				fallback = fallbackFactory.create(getExecutionException());
			}
	}
  1. PigxFeignFallbackFactory.create логика динамического прокси
	public T create(final Class<?> type, final Throwable cause) {
		return (T) FALLBACK_MAP.computeIfAbsent(type, key -> {
			Enhancer enhancer = new Enhancer();
			enhancer.setSuperclass(key);
			enhancer.setCallback(new PigxFeignFallbackMethod(type, cause));
			return enhancer.create();
		});
	}
  1. PigxFeignFallbackMethod.intercept, логика перехода на более раннюю версию по умолчанию, вывод информации о методе понижения версии и информации об ошибке, а также форматирование ошибки.
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) {
	log.error("Fallback class:[{}] method:[{}] message:[{}]",
			type.getName(), method.getName(), cause.getMessage());

	if (R.class == method.getReturnType()) {
		final R result = cause instanceof PigxFeignException ?
				((PigxFeignException) cause).getResult() : R.builder()
				.code(CommonConstants.FAIL)
				.msg(cause.getMessage()).build();
		return result;
	}
	return null;
}

Подписывайтесь на нас