Feign源码解析之注入IOC容器
Feign源码解析之生成jdk动态代理
Feign源码解析之代理类的处理逻辑
上一篇文章讲解了在springcloud项目中feign代理类和feign方法的处理逻辑,在实际项目中,feign经常和hystrix一起使用。hystrix是一种熔断机制,当某个时间单位内错误次数达到一定比例,hystrix会认为服务出现故障,触发熔断,后续请求不再走该服务,防止引发系统错误的雪崩效应。当熔断时间错误后,hystrx会向对应服务尝试一次请求,判断服务是否恢复。
接下来我们看一下是用来hystrix后feign的代理类和处理逻辑和原来相比有哪些变化。
曾经在feign中是默认使用hystrix,虽然在后续的版本中改为了默认不使用hyxtrix,不过要想启用feign的hystrix,只需要增加配置feign.hystrix.enabled:true。另外提一点,可以通过@EnableHystrix或@EnableCircuitBreaker在整个项目中使用hystrix。
当feign中使用了hystrix,根据FeignClientsConfiguration的HystrixFeignConfiguration和FeignAutoConfiguration的HystrixFeignTargeterConfiguration可以看出,IOC容器中注入的Feign.Builder类和HystrixTargeter发生了变化。
@Configuration
@ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
protected static class HystrixFeignConfiguration {
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
@ConditionalOnProperty(name = "feign.hystrix.enabled")
public Feign.Builder feignHystrixBuilder() {
return HystrixFeign.builder();
}
}
@Configuration
@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")
protected static class HystrixFeignTargeterConfiguration {
@Bean
@ConditionalOnMissingBean
public Targeter feignTargeter() {
return new HystrixTargeter();
}
}
从上一篇文章已经知道,Feign接口通过FeignClientFactoryBean的getObject方法委托targeter.target方法生成代理类,我们进行HystrixTargeter类的target方法。
@Override
public T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
Target.HardCodedTarget 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);
}
可以看出分4种情况:
1.非hyxtrix的feign builder类,走feign.target方法,这种情况用于用户自定义配置的场景,后续生成动态代理的逻辑由用户自行实现。
2.FeignClient带fallback属性,走targetWithFallback方法。
首先从applicationContext中根据类型获取fallback对象,因此在设置fallback属性时要注意两点:
(1)fallback类必须注入IOC容器
(2)fallback必须实现对应的feign类。
然后将fallback封装成fallbackFactory进行处理,后续代码与targetWithFallbackFactory相同,分析targetWithFallbackFactory方法时再展开。
private T targetWithFallback(String feignClientName, FeignContext context,
Target.HardCodedTarget target,
HystrixFeign.Builder builder, Class> fallback) {
T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type());
return builder.target(target, fallbackInstance);
}
private T getFromContext(String fallbackMechanism, String feignClientName, FeignContext context,
Class> beanType, Class 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;
}
public T target(Target target, T fallback) {
return build(fallback != null ? new FallbackFactory.Default(fallback) : null)
.newInstance(target);
}
3.FeignClient带fallbackFactory属性,走targetWithFallbackFactory方法。
同样的,首先从application获取到targetWithFallbackFactory对象,在设置fallbackFactory时需要注意两点。
(1)fallbackFactory必须注入IOC容器
(2)fallbackFactory的create方法返回值必须是接口类型或其子类型。
private T targetWithFallbackFactory(String feignClientName, FeignContext context,
Target.HardCodedTarget target,
HystrixFeign.Builder builder,
Class> fallbackFactoryClass) {
FallbackFactory extends T> fallbackFactory = (FallbackFactory extends T>)
getFromContext("fallbackFactory", feignClientName, context, fallbackFactoryClass, FallbackFactory.class);
/* We take a sample fallback from the fallback factory to check if it returns a fallback
that is compatible with the annotated feign interface. */
Object exampleFallback = fallbackFactory.create(new RuntimeException());
Assert.notNull(exampleFallback,
String.format(
"Incompatible fallbackFactory instance for feign client %s. Factory may not produce null!",
feignClientName));
if (!target.type().isAssignableFrom(exampleFallback.getClass())) {
throw new IllegalStateException(
String.format(
"Incompatible fallbackFactory instance for feign client %s. Factory produces instances of '%s', but should produce instances of '%s'",
feignClientName, exampleFallback.getClass(), target.type()));
}
return builder.target(target, fallbackFactory);
}
public T target(Target target, FallbackFactory extends T> fallbackFactory) {
return build(fallbackFactory).newInstance(target);
}
接着看build方法,可以看出,和其父类的build方法(Feign默认的build逻辑)相比,只是修改了其InvocationHandlerFactory属性和ParseHandlersByName属性的contract属性,返回的依旧是ReflevtiveFeign方法,后续的逻辑和上一篇的feign默认的逻辑相同,不再展开。
Feign build(final FallbackFactory> nullableFallbackFactory) {
super.invocationHandlerFactory(new InvocationHandlerFactory() {
@Override public InvocationHandler create(Target target,
Map dispatch) {
return new HystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory);
}
});
super.contract(new HystrixDelegatingContract(contract));
return super.build();
}
那么,修改了ReflevtiveFeign的InvocationHandlerFactory类型的属性会产生什么影响呢?
这一属性修改对应的是ReflectiveFeign的newInstance方法的InvocationHandler handler = factory.create(target, methodToHandler);
语句的执行结果。
默认的不带hystrix的逻辑会调用InvocationHandlerFactory.Default方法得到FeignInvocationHandler类,而带hystrix的feign逻辑从上文对应invocationHandlerFactory的匿名类可以看出,返回的是HystrixInvocationHandler,代理类处理方法时的逻辑自然发生了变化。
static final class Default implements InvocationHandlerFactory {
@Override
public InvocationHandler create(Target target, Map dispatch) {
return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
}
}
修改了ReflevtiveFeign的ParseHandlersByName属性的contract属性会产生什么影响呢?
这一属性的修改对应的是ReflectiveFeign的newInstance方法的Map
语句,更细致点说对应ParseHandlersByName类的apply方法的List
语句,由Feign方法到MethodMetaData的逻辑发生了变化。
接下来仔细看看发生了什么变化,如下文,这里的delegate对应的就是Feign中的默认Contract,因此可以看出在执行完原先Feign的处理逻辑之后,HystrixDelegatingContract又在其后进行遍历增加了对返回类型的额外判断和处理。
@Override
public List parseAndValidatateMetadata(Class> targetType) {
List metadatas = this.delegate.parseAndValidatateMetadata(targetType);
for (MethodMetadata metadata : metadatas) {
Type type = metadata.returnType();
if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType().equals(HystrixCommand.class) {
Type actualType = resolveLastTypeParameter(type, HystrixCommand.class);
metadata.returnType(actualType);
} else if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType().equals(Observable.class)) {
Type actualType = resolveLastTypeParameter(type, Observable.class);
metadata.returnType(actualType);
} else if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType().equals(Single.class)) {
Type actualType = resolveLastTypeParameter(type, Single.class);
metadata.returnType(actualType);
} else if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType().equals(Completable.class)) {
metadata.returnType(void.class);
}
}
return metadatas;
}
ParameterizedType表示参数化类型,即泛型,如Collection
HystrixDelegatingContract针对返回类型是泛型的方法且getRawType为hystrix中特殊类的方法做处理,getRawType为HystrixCommand、Observable、Single类型都由resolveLastTypeParameter获取到返回值,Completable返回值类型设置为void。
4.FeignClient没有设置回滚,走feign.target。
此时按fallbackFactory为null作为参数条用build方法,其它逻辑与上述的一致。
@Override
public Feign build() {
return build(null);
}
二. HystrixInvocationHandler的invoke方法
最后,看一看启用了hystrix的feign对应的HystrixInvocationHandler的invoke方法,分4步:
1.对于equals、hashCode、toString的方法处理,和FeignInvocationHandler相同。
2.封装成hystrixCommand,包括执行逻辑run和回滚逻辑fallback。
run方法的执行逻辑和FeignInvocationHandler也基本一致,当然不是和FeignInvocationHandler一样简单的同步执行http请求并返回,而是交个hystrix统一管理。
fallback交给之前传入的参数fallbackFactory生成,如果fallbackFactory为null,则直接抛出异常,否则交给自定义的回滚类处理。
3.返回值为HystrixCommand、Observable、Single、Completable的特殊处理。
4.执行hystrixCommand的execute方法,
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args)
throws Throwable {
// early exit if the invoked method is from java.lang.Object
// code is the same as ReflectiveFeign.FeignInvocationHandler
if ("equals".equals(method.getName())) {
try {
Object otherHandler =
args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
return equals(otherHandler);
} catch (IllegalArgumentException e) {
return false;
}
} else if ("hashCode".equals(method.getName())) {
return hashCode();
} else if ("toString".equals(method.getName())) {
return toString();
}
HystrixCommand