Feign集成Hystrix源碼分析(Targeter實現類)

緣起: Feign集成Hystrix源碼分析(自動配置)

Targeter接口

上章詳解了,加了@FeignClient的類最後注入的bean類型是Targeter.target返回的值

protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
			HardCodedTarget<T> target) {
		Client client = getOptional(context, Client.class);
		if (client != null) {
			builder.client(client);
			// 找到容器中bean類型爲Targeter的bean
			Targeter targeter = get(context, Targeter.class);
			return targeter.target(this, builder, context, target);
		}
		throw new IllegalStateException(
				"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
	}

這裏會根據Targeter.class找到實現了Targeter接口的bean
默認定好了兩個實現了Targeter接口的類,但只會注入一個到容器中

	@Configuration
	@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")
	protected static class HystrixFeignTargeterConfiguration {

		@Bean
		@ConditionalOnMissingBean
		public Targeter feignTargeter() {
			return new HystrixTargeter();
		}

	}

	@Configuration
	@ConditionalOnMissingClass("feign.hystrix.HystrixFeign")
	protected static class DefaultFeignTargeterConfiguration {

		@Bean
		@ConditionalOnMissingBean
		public Targeter feignTargeter() {
			return new DefaultTargeter();
		}

	}

DefaultTargeter

DefaultTargeter是默認的實現,不會進行降級處理

class DefaultTargeter implements Targeter {

	@Override
	public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
			FeignContext context, Target.HardCodedTarget<T> target) {
		return feign.target(target);
	}

}

HystrixTargeter

class HystrixTargeter implements Targeter {

	@Override
	public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
			FeignContext context, Target.HardCodedTarget<T> target) {、
		
		if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
			return feign.target(target);
		}
		feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
		SetterFactory setterFactory = getOptional(factory.getName(), context,
				SetterFactory.class);
		if (setterFactory != null) {
			builder.setterFactory(setterFactory);
		}
		Class<?> fallback = factory.getFallback();
		if (fallback != void.class) {
			return targetWithFallback(factory.getName(), context, target, builder,
					fallback);
		}
		Class<?> fallbackFactory = factory.getFallbackFactory();
		if (fallbackFactory != void.class) {
			return targetWithFallbackFactory(factory.getName(), context, target, builder,
					fallbackFactory);
		}

		return feign.target(target);
	}

	private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,
			Target.HardCodedTarget<T> target, HystrixFeign.Builder builder,
			Class<?> fallbackFactoryClass) {
		FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>) getFromContext(
				"fallbackFactory", feignClientName, context, fallbackFactoryClass,
				FallbackFactory.class);
		return builder.target(target, fallbackFactory);
	}

	private <T> T targetWithFallback(String feignClientName, FeignContext context,
			Target.HardCodedTarget<T> target, HystrixFeign.Builder builder,
			Class<?> fallback) {
		T fallbackInstance = getFromContext("fallback", feignClientName, context,
				fallback, target.type());
		return builder.target(target, fallbackInstance);
	}

	private <T> T getFromContext(String fallbackMechanism, String feignClientName,
			FeignContext context, Class<?> beanType, Class<T> targetType) {
		Object fallbackInstance = context.getInstance(feignClientName, beanType);
		if (fallbackInstance == null) {
			throw new IllegalStateException(String.format(
					"No " + fallbackMechanism
							+ " instance of type %s found for feign client %s",
					beanType, feignClientName));
		}

		if (!targetType.isAssignableFrom(beanType)) {
			throw new IllegalStateException(String.format("Incompatible "
					+ fallbackMechanism
					+ " instance. Fallback/fallbackFactory of type %s is not assignable to %s for feign client %s",
					beanType, targetType, feignClientName));
		}
		return (T) fallbackInstance;
	}

	private <T> T getOptional(String feignClientName, FeignContext context,
			Class<T> beanType) {
		return context.getInstance(feignClientName, beanType);
	}

}

是否開啓feign.hystrix.enabled

判斷當前Feign.Builder類型是不是HystrixFeign.builder()
因爲只有當feign.hystrix.enabled=true

@Bean
@Scope("prototype")
@ConditionalOnMissingBean
@ConditionalOnProperty(name = "feign.hystrix.enabled")
public Feign.Builder feignHystrixBuilder() {
	return HystrixFeign.builder();
}

feign.hystrix.enabled=false

@Bean
@Scope("prototype")
@ConditionalOnMissingBean
public Feign.Builder feignBuilder(Retryer retryer) {
	return Feign.builder().retryer(retryer);
}

也就是說,沒有開啓降級處理時,直接執行return feign.target(target);

fallback

爲Feign客戶端的定義接口編寫一個具體的接口實現類,比如爲HelloService接口實現一個服務降級類HelloServicFallback,其中每個重寫方法的實現邏輯都可以用來定義相應的服務降級邏輯

@FeignClient(value = "hello-service",fallback = HelloServiceFallback.class)
@Service
public interface HelloService {
    @RequestMapping("/hello")
    String hello();
 
    @RequestMapping("/hello1")
    String hello(@RequestParam("name") String name);
 
    @RequestMapping("/hello2")
    User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age);
 
    @RequestMapping("/hello3")
    String hello(@RequestBody User user);
 
}
@Component
public class HelloServiceFallback implements HelloService {
    @Override
    public String hello() {
        return "error";
    }
 
    @Override
    public String hello(String name) {
        return "error";
    }
 
    @Override
    public User hello(String name, Integer age) {
        return new User("未知",0);
    }
 
    @Override
    public String hello(User user) {
        return "error";
    }
}

HystrixTargeter

Class<?> fallback = factory.getFallback();
if (fallback != void.class) {
	return targetWithFallback(factory.getName(), context, target, builder,
			fallback);
}

private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,
			Target.HardCodedTarget<T> target, HystrixFeign.Builder builder,
			Class<?> fallbackFactoryClass) {
		FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>) getFromContext(
				"fallbackFactory", feignClientName, context, fallbackFactoryClass,
				FallbackFactory.class);
		return builder.target(target, fallbackFactory);
	}

fallbackFactory

需要自定義實現FallbackFactory接口,重寫T create(Throwable cause)方法,然後在@FeignClient中指定fallbackFactory

@FeignClient(name="spring-boot-user", fallbackFactory=HystrixClientFallbackFactory.class)
public interface UserFeignClient {
 
    @RequestMapping(value="/simple/{id}", method=RequestMethod.GET)
    public User findById(@PathVariable("id") Long id); 
 
}

public interface HystrixClientWithFallbackFactory extends UserFeignClient {
 
}

@Component
public class HystrixClientFallbackFactory implements FallbackFactory<UserFeignClient> {
 
    @Override
    public UserFeignClient create(Throwable arg0) {
        // TODO Auto-generated method stub
        return new HystrixClientWithFallbackFactory() {
 
            @Override
            public User findById(Long id) {
                // TODO Auto-generated method stub
                User user = new User();
                user.setId(-1L);
                return user;
            }
             
        };
    }
 
}

HystrixTargeter

Class<?> fallbackFactory = factory.getFallbackFactory();
		if (fallbackFactory != void.class) {
			return targetWithFallbackFactory(factory.getName(), context, target, builder,
					fallbackFactory);
		}

private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,
			Target.HardCodedTarget<T> target, HystrixFeign.Builder builder,
			Class<?> fallbackFactoryClass) {
		FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>) getFromContext(
				"fallbackFactory", feignClientName, context, fallbackFactoryClass,
				FallbackFactory.class);
		return builder.target(target, fallbackFactory);
	}

沒有指定fallback與fallbackFactory

如果在@FeignClient沒有指定fallbackfallbackFactory,則最後走return feign.target(target);,即不降級處理

自定義全局降級處理

我們看到,要實現hystrix降級處理,必須指定fallbackfallbackFactory,但是每一個feign接口方法都要寫相應的降級方法,太過有點繁瑣了。
我們可以仿照之前寫過的fallbackFactory,最後執行的是重寫的T create(Throwable cause)方法,但是之前的fallbackFactory很侷限性,每個接口的方法都要重寫。
我們可以自定義FallbackFactory實現類,然後通過動態代理增強加了@FeignClient註解的接口方法
然後在自定義Targeter實現類中調用

MyFallbackFactory pigxFallbackFactory = new MyFallbackFactory (target);
return (T) builder.target(target, pigxFallbackFactory);

自定義FallbackFactory實現類

通過cglib動動態代理增強加了@FeignClient註解的接口方法,以前都是單獨實現接口方法。

@AllArgsConstructor
public class TCloudFallbackFactory<T> implements FallbackFactory<T> {
	private final Target<T> target;

	@Override
	@SuppressWarnings("unchecked")
	public T create(Throwable cause) {
		// @FeignClient註解的接口類型
		final Class<T> targetType = target.type();
		final String targetName = target.name();
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(targetType);
		enhancer.setUseCache(true);
		enhancer.setCallback(new TCloudFeignFallback<>(targetType, targetName, cause));
		return (T) enhancer.create();
	}
}

create是怎麼被調用的,這一部分在源碼中體現在HystrixInvocationHandler.java
在這裏插入圖片描述

cglib代理處理類

@Slf4j
@AllArgsConstructor
public class MyFeignFallback<T> implements MethodInterceptor {
	private final Class<T> targetType;
	private final String targetName;
	private final Throwable cause;

	@Nullable
	@Override
	public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
		Class<?> returnType = method.getReturnType();
		if (R.class != returnType) {
			return null;
		}
		FeignException exception = (FeignException) cause;

		byte[] content = exception.content();

		String str = StrUtil.str(content, StandardCharsets.UTF_8);

		// 降級信息
		log.error("MyFeignFallback:[{}.{}] serviceId:[{}] message:[{}]", targetType.getName(), method.getName(), targetName, str);
		return R.builder().code(CommonConstants.FAIL)
				.msg(str).build();
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}
		MyFeignFallback<?> that = (MyFeignFallback<?>) o;
		return targetType.equals(that.targetType);
	}

	@Override
	public int hashCode() {
		return Objects.hash(targetType);
	}
}

自定義Targeter實現類

@Primary
@Configuration
@ConditionalOnClass(HystrixFeign.class)
@ConditionalOnProperty("feign.hystrix.enabled")
class MyHystrixTargeter implements Targeter {

	@Override
	public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
						Target.HardCodedTarget<T> target) {
		if (!(feign instanceof HystrixFeign.Builder)) {
			return feign.target(target);
		}
		HystrixFeign.Builder builder = (HystrixFeign.Builder) feign;
		SetterFactory setterFactory = getOptional(factory.getName(), context, SetterFactory.class);
		if (setterFactory != null) {
			builder.setterFactory(setterFactory);
		}
		Class<?> fallback = factory.getFallback();
		if (fallback != void.class) {
			return targetWithFallback(factory.getName(), context, target, builder, fallback);
		}
		Class<?> fallbackFactory = factory.getFallbackFactory();
		if (fallbackFactory != void.class) {
			return targetWithFallbackFactory(factory.getName(), context, target, builder, fallbackFactory);
		}

		// 設置自定義的FallbackFactory
		MyFallbackFactory pigxFallbackFactory = new MyFallbackFactory(target);
		return (T) builder.target(target, pigxFallbackFactory);
	}

	private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,
											Target.HardCodedTarget<T> target,
											HystrixFeign.Builder builder,
											Class<?> fallbackFactoryClass) {
		FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>)
				getFromContext("fallbackFactory", feignClientName, context, fallbackFactoryClass, FallbackFactory.class);
		return builder.target(target, fallbackFactory);
	}


	private <T> T targetWithFallback(String feignClientName, FeignContext context,
									 Target.HardCodedTarget<T> target,
									 HystrixFeign.Builder builder, Class<?> fallback) {
		T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type());
		return builder.target(target, fallbackInstance);
	}

	private <T> T getFromContext(String fallbackMechanism, String feignClientName, FeignContext context, Class<?> beanType,
								 Class<T> targetType) {
		Object fallbackInstance = context.getInstance(feignClientName, beanType);
		if (fallbackInstance == null) {
			throw new IllegalStateException(String.format("No " + fallbackMechanism +
					" instance of type %s found for feign client %s", beanType, feignClientName));
		}

		if (!targetType.isAssignableFrom(beanType)) {
			throw new IllegalStateException(String.format(
					"Incompatible " + fallbackMechanism + " instance. Fallback/fallbackFactory of " +
							"type %s is not assignable to %s for feign client %s", beanType, targetType, feignClientName));
		}
		return (T) fallbackInstance;
	}

	@Nullable
	private <T> T getOptional(String feignClientName, FeignContext context, Class<T> beanType) {
		return context.getInstance(feignClientName, beanType);
	}

注意,自定義Targeter實現類一定要加上@Primary
因爲在FeignClientFactoryBean中是根據Targeter.class類型獲取Targeter實例
而feign內部已經裝配了其他Targeter實現類,比如HystrixTargeter
在這裏插入圖片描述
下章節,Targeter執行過程源碼分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章