Feign使用简单示例
定义好一个接口,用@RequestLine注解
public interface WxCorpDepartmentClient {
@RequestLine("POST /cgi-bin/department/list?access_token={accessToken}")
public DepartmentResult departments(@Param("accessToken") String accessToken);
}
实际发起请求的代码:
@Component
public class WxCorpPermanentCodeClientImpl extends BaseWxCorpClient implements WxCorpPermanentCodeClient {
@Override
public PermanentCodeResult corpPermanentCode(String suiteAccessToken, PermanentCodeRequest permanentCodeRequest) {
return getFeignClient(WxCorpPermanentCodeClient.class).corpPermanentCode(suiteAccessToken, permanentCodeRequest);
}
}
public class BaseWxCorpClient {
public T getFeignClient(Class clazz) {
return Feign.builder()
.encoder(new GsonEncoder())
.decoder(new GsonDecoder()).target(clazz, "https://qyapi.weixin.qq.com");
}
}
源代码解析
核心类类图
由类图可知,Feign的实例的Class为 feign.ReflectiveFeign
ReflectiveFeign的创建过程
该实例采用Builder模式进行创建,在通常的使用中,我们写如下代码即可创建ReflectiveFeign的实例。
Feign.builder().encoder(new GsonEncoder()).decoder(new GsonDecoder()).target(clazz, "https://qyapi.weixin.qq.com")
Feign.builder()
通过Feign.builder()创建出Feign的构造器实例。在Builder的属性中,可以看到包括 Client、Retryer、Logger、Encoder、Decoder、Contract、Logger.Level等都是可以进行定义的。不过在builder中也对这些属性做了默认的配置。
private Logger.Level logLevel = Logger.Level.NONE;
private Contract contract = new Contract.Default();
private Client client = new Client.Default(null, null);
private Retryer retryer = new Retryer.Default();
private Logger logger = new NoOpLogger();
private Encoder encoder = new Encoder.Default();
private Decoder decoder = new Decoder.Default();
private ErrorDecoder errorDecoder = new ErrorDecoder.Default();
Builder.target(Class, String)
public T target(Class apiType, String url) {
return target(new HardCodedTarget(apiType, url));
}
public T target(Target target) {
return build().newInstance(target);
}
public Feign build() {
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404);
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder,
errorDecoder, synchronousMethodHandlerFactory);
return new ReflectiveFeign(handlersByName, invocationHandlerFactory);
}
通过Builder.build()方法,最后创建出ReflectiveFeign的实例。
ReflectiveFeign的两个属性,一个是ParseHandlersByName 另一个是InvocationHandlerFactory。
Feign.newInstance(Target)
在ReflectiveFeign中对newInstance方法的实现为:
public T newInstance(Target target) {
// 将Target包装的实际的对象的方法进行分析后,封装在map里.key就是方法的签名.
Map nameToHandler = targetToHandlersByName.apply(target);
Map methodToHandler = new LinkedHashMap();
List defaultMethodHandlers = new LinkedList();
for (Method method : target.type().getMethods()) {
if (method.getDeclaringClass() == Object.class) {
continue;
} else if(Util.isDefault(method)) {
DefaultMethodHandler handler = new DefaultMethodHandler(method);
defaultMethodHandlers.add(handler);
methodToHandler.put(method, handler);
} else {
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
InvocationHandler handler = factory.create(target, methodToHandler);
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class>[]{target.type()}, handler);
for(DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
对应的nameToHanlder在内存中的调试结果为:
Feign对我们的接口做了代理,具体的实现是在 feign.ReflectiveFeign.FeignInvocationHandler 这个类中。
static class FeignInvocationHandler implements InvocationHandler {
private final Target target;
private final Map dispatch;
FeignInvocationHandler(Target target, Map dispatch) {
this.target = checkNotNull(target, "target");
this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
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();
}
return dispatch.get(method).invoke(args);
}
}
由代理对象的invoke可知,我们在实际调用接口方法的时候,会调用其invoke方法。
invoke方法中,根据方法获取到对应的MethodHandler,由调试的内存结果,我们看到是由SynchronousMethodHandler来进行处理的。下面是对应的invoke的处理逻辑。
@Override
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = buildTemplateFromArgs.create(argv);
Retryer retryer = this.retryer.clone();
while (true) {
try {
return executeAndDecode(template);
} catch (RetryableException e) {
retryer.continueOrPropagate(e);
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}