共计 8073 个字符,预计需要花费 21 分钟才能阅读完成。
序
本文主要研究一下 feign 的 HystrixInvocationHandler
HystrixInvocationHandler
feign-hystrix-10.2.3-sources.jar!/feign/hystrix/HystrixInvocationHandler.java
final class HystrixInvocationHandler implements InvocationHandler { | |
private final Target<?> target; | |
private final Map<Method, MethodHandler> dispatch; | |
private final FallbackFactory<?> fallbackFactory; // Nullable | |
private final Map<Method, Method> fallbackMethodMap; | |
private final Map<Method, Setter> setterMethodMap; | |
HystrixInvocationHandler(Target<?> target, Map<Method, MethodHandler> dispatch, | |
SetterFactory setterFactory, FallbackFactory<?> fallbackFactory) {this.target = checkNotNull(target, "target"); | |
this.dispatch = checkNotNull(dispatch, "dispatch"); | |
this.fallbackFactory = fallbackFactory; | |
this.fallbackMethodMap = toFallbackMethod(dispatch); | |
this.setterMethodMap = toSetters(setterFactory, target, dispatch.keySet()); | |
} | |
/** | |
* If the method param of InvocationHandler.invoke is not accessible, i.e in a package-private | |
* interface, the fallback call in hystrix command will fail cause of access restrictions. But | |
* methods in dispatch are copied methods. So setting access to dispatch method doesn't take | |
* effect to the method in InvocationHandler.invoke. Use map to store a copy of method to invoke | |
* the fallback to bypass this and reducing the count of reflection calls. | |
* | |
* @return cached methods map for fallback invoking | |
*/ | |
static Map<Method, Method> toFallbackMethod(Map<Method, MethodHandler> dispatch) {Map<Method, Method> result = new LinkedHashMap<Method, Method>(); | |
for (Method method : dispatch.keySet()) {method.setAccessible(true); | |
result.put(method, method); | |
} | |
return result; | |
} | |
/** | |
* Process all methods in the target so that appropriate setters are created. | |
*/ | |
static Map<Method, Setter> toSetters(SetterFactory setterFactory, | |
Target<?> target, | |
Set<Method> methods) {Map<Method, Setter> result = new LinkedHashMap<Method, Setter>(); | |
for (Method method : methods) {method.setAccessible(true); | |
result.put(method, setterFactory.create(target, method)); | |
} | |
return result; | |
} | |
@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<Object> hystrixCommand = | |
new HystrixCommand<Object>(setterMethodMap.get(method)) { | |
@Override | |
protected Object run() throws Exception { | |
try {return HystrixInvocationHandler.this.dispatch.get(method).invoke(args); | |
} catch (Exception e) {throw e;} catch (Throwable t) {throw (Error) t; | |
} | |
} | |
@Override | |
protected Object getFallback() {if (fallbackFactory == null) {return super.getFallback(); | |
} | |
try {Object fallback = fallbackFactory.create(getExecutionException()); | |
Object result = fallbackMethodMap.get(method).invoke(fallback, args); | |
if (isReturnsHystrixCommand(method)) {return ((HystrixCommand) result).execute();} else if (isReturnsObservable(method)) { | |
// Create a cold Observable | |
return ((Observable) result).toBlocking().first(); | |
} else if (isReturnsSingle(method)) { | |
// Create a cold Observable as a Single | |
return ((Single) result).toObservable().toBlocking().first();} else if (isReturnsCompletable(method)) {((Completable) result).await(); | |
return null; | |
} else if (isReturnsCompletableFuture(method)) {return ((Future) result).get();} else {return result;} | |
} catch (IllegalAccessException e) { | |
// shouldn't happen as method is public due to being an interface | |
throw new AssertionError(e); | |
} catch (InvocationTargetException | ExecutionException e) { | |
// Exceptions on fallback are tossed by Hystrix | |
throw new AssertionError(e.getCause()); | |
} catch (InterruptedException e) { | |
// Exceptions on fallback are tossed by Hystrix | |
Thread.currentThread().interrupt(); | |
throw new AssertionError(e.getCause()); | |
} | |
} | |
}; | |
if (Util.isDefault(method)) {return hystrixCommand.execute(); | |
} else if (isReturnsHystrixCommand(method)) {return hystrixCommand;} else if (isReturnsObservable(method)) { | |
// Create a cold Observable | |
return hystrixCommand.toObservable();} else if (isReturnsSingle(method)) { | |
// Create a cold Observable as a Single | |
return hystrixCommand.toObservable().toSingle(); | |
} else if (isReturnsCompletable(method)) {return hystrixCommand.toObservable().toCompletable();} else if (isReturnsCompletableFuture(method)) {return new ObservableCompletableFuture<>(hystrixCommand); | |
} | |
return hystrixCommand.execute();} | |
private boolean isReturnsCompletable(Method method) {return Completable.class.isAssignableFrom(method.getReturnType()); | |
} | |
private boolean isReturnsHystrixCommand(Method method) {return HystrixCommand.class.isAssignableFrom(method.getReturnType()); | |
} | |
private boolean isReturnsObservable(Method method) {return Observable.class.isAssignableFrom(method.getReturnType()); | |
} | |
private boolean isReturnsCompletableFuture(Method method) {return CompletableFuture.class.isAssignableFrom(method.getReturnType()); | |
} | |
private boolean isReturnsSingle(Method method) {return Single.class.isAssignableFrom(method.getReturnType()); | |
} | |
@Override | |
public boolean equals(Object obj) {if (obj instanceof HystrixInvocationHandler) {HystrixInvocationHandler other = (HystrixInvocationHandler) obj; | |
return target.equals(other.target); | |
} | |
return false; | |
} | |
@Override | |
public int hashCode() {return target.hashCode(); | |
} | |
@Override | |
public String toString() {return target.toString(); | |
} | |
} |
- HystrixInvocationHandler 实现了 InvocationHandler 接口,其构造器接收 target、dispatch、setterFactory、fallbackFactory;invoke 方法主要是创建 hystrixCommand,然后执行 hystrixCommand 的 execute 或 toObservable 等方法;hystrixCommand 的 run 方法执行 HystrixInvocationHandler.this.dispatch.get(method).invoke(args),其 getFallback 方法主要是执行 fallbackMethodMap.get(method).invoke(fallback, args)
InvocationHandlerFactory
feign-core-10.2.3-sources.jar!/feign/InvocationHandlerFactory.java
public interface InvocationHandlerFactory {InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch); | |
/** | |
* Like {@link InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])}, except for a | |
* single method. | |
*/ | |
interface MethodHandler {Object invoke(Object[] argv) throws Throwable; | |
} | |
static final class Default implements InvocationHandlerFactory { | |
@Override | |
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {return new ReflectiveFeign.FeignInvocationHandler(target, dispatch); | |
} | |
} | |
} |
- InvocationHandlerFactory 接口定义了 create 方法用于创建 InvocationHandler;它有一个 Default 的实现,其 create 方法创建的是 ReflectiveFeign.FeignInvocationHandler
HystrixFeign
feign-hystrix-10.2.3-sources.jar!/feign/hystrix/HystrixFeign.java
public final class HystrixFeign { | |
//...... | |
public static final class Builder extends Feign.Builder {private Contract contract = new Contract.Default(); | |
private SetterFactory setterFactory = new SetterFactory.Default(); | |
//...... | |
@Override | |
public Feign build() {return build(null); | |
} | |
/** Configures components needed for hystrix integration. */ | |
Feign build(final FallbackFactory<?> nullableFallbackFactory) {super.invocationHandlerFactory(new InvocationHandlerFactory() { | |
@Override | |
public InvocationHandler create(Target target, | |
Map<Method, MethodHandler> dispatch) { | |
return new HystrixInvocationHandler(target, dispatch, setterFactory, | |
nullableFallbackFactory); | |
} | |
}); | |
super.contract(new HystrixDelegatingContract(contract)); | |
return super.build();} | |
//...... | |
} | |
//...... | |
} |
- HystrixFeign.Builder 的 build 方法使用的 InvocationHandlerFactory 创建的是 HystrixInvocationHandler
FeignClientsConfiguration
spring-cloud-openfeign-core-2.2.0.M1-sources.jar!/org/springframework/cloud/openfeign/FeignClientsConfiguration.java
@Configuration | |
public class FeignClientsConfiguration { | |
//...... | |
@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(); | |
} | |
} | |
//...... | |
} |
- FeignClientsConfiguration 的 HystrixFeignConfiguration 在有 HystrixCommand.class, HystrixFeign.class 以及 feign.hystrix.enabled 为 true 的情况下,其创建的 Feign.Builder 为 HystrixFeign.builder
小结
HystrixInvocationHandler 实现了 InvocationHandler 接口,其构造器接收 target、dispatch、setterFactory、fallbackFactory;invoke 方法主要是创建 hystrixCommand,然后执行 hystrixCommand 的 execute 或 toObservable 等方法;hystrixCommand 的 run 方法执行 HystrixInvocationHandler.this.dispatch.get(method).invoke(args),其 getFallback 方法主要是执行 fallbackMethodMap.get(method).invoke(fallback, args)
doc
- HystrixInvocationHandler
正文完