Feign集成Hystrix源码分析(Targeter实现类)

2022-08-03 10:35:16

缘起: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执行过程源码分析

  • 作者:浴缸灬
  • 原文链接:https://blog.csdn.net/yu_kang/article/details/100156207
    更新时间:2022-08-03 10:35:16