当我们在使用的时候首先启用Feign,即 启动类中添加注解@EnableFeignClients
@EnableFeignClients
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
进入@EnableFeignClients注解类中
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
}
关于@Import的使用可以查看@Import注解了解,此处加载FeignClientsRegistrar类,我们可以继续进入该类中
class FeignClientsRegistrar
implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
}
FeignClientsRegistrar有多个接口实现,ImportBeanDefinitionRegistrar用于自定义实现Bean定义信息、ResourceLoaderAware、EnvironmentAware
我们重点看下ImportBeanDefinitionRegistrar的接口方法registerBeanDefinitions的实现
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
registerDefaultConfiguration(metadata, registry);
registerFeignClients(metadata, registry);
}
其中registerDefaultConfiguration(metadata, registry);方法主要是获取@EnableFeignClients注解参数defaultConfiguration的值…
我们重点看下registerFeignClients(metadata, registry);
public void registerFeignClients(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();
//获取注解中的属性信息
Map<String, Object> attrs = metadata
.getAnnotationAttributes(EnableFeignClients.class.getName());
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
FeignClient.class);
final Class<?>[] clients = attrs == null ? null
: (Class<?>[]) attrs.get("clients");
//如果没有clients配置信息,则取获取所有@FeignClient 标注的类
if (clients == null || clients.length == 0) {
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));
Set<String> basePackages = getBasePackages(metadata);
for (String basePackage : basePackages) {
//存放被@FeignClient标注的类的定义信息(BeanDefinition)
candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
}
}
//如果有指定的clients信息 会走到该逻辑
else {
for (Class<?> clazz : clients) {
candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz));
}
}
//循环遍历@FeignClient标注的类的BeanDefinition
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition) {
//验证带注解的类是否为接口
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Assert.isTrue(annotationMetadata.isInterface(),
"@FeignClient can only be specified on an interface");
//获取@FeignClient的属性信息
Map<String, Object> attributes = annotationMetadata
.getAnnotationAttributes(FeignClient.class.getCanonicalName());
//获取名称
String name = getClientName(attributes);
//将一些配置信息添加到 registry的BeanDefinition集合中(编码器、解码器等)
registerClientConfiguration(registry, name,
attributes.get("configuration"));
//注册FeignClient
registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
我们还是重点关注下registerFeignClient方法的调用,我们需要重点留意下 有设置 FeignClientFactoryBean(表示注册的FeignClient都是FeignClientFactoryBean类型的)
private void registerFeignClient(BeanDefinitionRegistry registry,
AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
//获取当前被@FeignClient标注的类名
String className = annotationMetadata.getClassName();
//通过建造者模式创建BeanDefinition
//BeanDefinitionBuilder中含有属性beanDefinition(GenericBeanDefinition类型)
//beanDefinition设置beanClass(Class类型)为FeignClientFactoryBean.class
**BeanDefinitionBuilder definition = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);**
validate(attributes);
definition.addPropertyValue("url", getUrl(attributes));
definition.addPropertyValue("path", getPath(attributes));
String name = getName(attributes);
definition.addPropertyValue("name", name);
String contextId = getContextId(attributes);
definition.addPropertyValue("contextId", contextId);
definition.addPropertyValue("type", className);
definition.addPropertyValue("decode404", attributes.get("decode404"));
definition.addPropertyValue("fallback", attributes.get("fallback"));
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
String alias = contextId + "FeignClient";
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
// has a default, won't be null
boolean primary = (Boolean) attributes.get("primary");
beanDefinition.setPrimary(primary);
String qualifier = getQualifier(attributes);
if (StringUtils.hasText(qualifier)) {
alias = qualifier;
}
//创建BeanDefinitionHolder
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
new String[] { alias });
//注册FeignClient的BeanDefinition信息
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
我们继续重点看下BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);方法
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
//注册
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
假设我们有一个IRemoteCallService类
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@FeignClient(name="server-user")
public interface IRemoteCallService {
@RequestMapping(value="/user/getNameById",method = RequestMethod.POST)
String getName(@RequestParam("userId") String userId);
}
当我们执行context.getBean(IRemoteCallService.class);时
@EnableFeignClients
public class GatewayApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(GatewayApplication.class, args);
IRemoteCallService bean = context.getBean(IRemoteCallService.class);
}
}
中间具体细节调用流程为:
org.springframework.context.support.AbstractApplicationContext#getBean(java.lang.Class)
org.springframework.beans.factory.support.DefaultListableBeanFactory#getBean(java.lang.Class)
org.springframework.beans.factory.support.DefaultListableBeanFactory#getBean(java.lang.Class, java.lang.Object…)
org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveBean
org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveNamedBean(org.springframework.core.ResolvableType, java.lang.Object[], boolean)
org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String, java.lang.Class, java.lang.Object…)
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
我们看下doGetBean中部分方法:
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
//mbd 是 GenericBeanDefinition转化而来的
RootBeanDefinition mbdToUse = mbd;
//获得beanClass,即:FeignClientFactoryBean
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
try {
mbdToUse.prepareMethodOverrides();
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
//可以通过调用BeanPostProcessors来完成实例
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
try {
//调用doCreateBean方法,
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
}
我们继续看下 doCreateBean方法
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//实例化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
...
}
createBeanInstance方法调用
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
//beanClass :FeignClientFactoryBean
Class<?> beanClass = resolveBeanClass(mbd, beanName);
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
//调用构造方法实例化
return instantiateBean(beanName, mbd);
}
我们继续返回到doGetBean方法中,调用完createBean方法后,继续调用getObjectForBeanInstance方法
org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
//此时我们拿到的 beanInstance 是 FeignClientFactoryBean的实例,FeignClientFactoryBean是实现了FactoryBean接口的
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
//获取缓存
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// 缓存获取Bean定义信息
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
//获取Object
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
else {
//调用doGetObjectFromFactoryBean方法
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
Object object;
try {
else {
//调用FeignClientFactoryBean的getObject方法
object = factory.getObject();
}
}
}
org.springframework.cloud.openfeign.FeignClientFactoryBean#getObject
@Override
public Object getObject() throws Exception {
return getTarget();
}
<T> T getTarget() {
//获取FeignClientSpecification中存放的配置信息(编码器、解码器)
FeignContext context = applicationContext.getBean(FeignContext.class);
Feign.Builder builder = feign(context);
//组装url,(http://server-user)
if (!StringUtils.hasText(url)) {
if (!name.startsWith("http")) {
url = "http://" + name;
}
else {
url = name;
}
url += cleanPath();
return (T) loadBalance(builder, context,
new HardCodedTarget<>(type, name, url));
}
if (StringUtils.hasText(url) && !url.startsWith("http")) {
url = "http://" + url;
}
String url = this.url + cleanPath();
Client client = getOptional(context, Client.class);
if (client != null) {
if (client instanceof LoadBalancerFeignClient) {
client = ((LoadBalancerFeignClient) client).getDelegate();
}
if (client instanceof FeignBlockingLoadBalancerClient) {
client = ((FeignBlockingLoadBalancerClient) client).getDelegate();
}
builder.client(client);
}
//
Targeter targeter = get(context, Targeter.class);
//生成代理
return (T) targeter.target(this, builder, context,
new HardCodedTarget<>(type, name, url));
}
调用org.springframework.cloud.openfeign.DefaultTargeter#target
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
return feign.target(target);
}
调用 feign.Feign.Builder#target(feign.Target)
public <T> T target(Target<T> target) {
return build().newInstance(target);
}
调用 feign.Feign.Builder#build
private InvocationHandlerFactory invocationHandlerFactory = new InvocationHandlerFactory.Default();
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);
//生成ReflectiveFeign,
return new ReflectiveFeign(handlersByName, invocationHandlerFactory);
}
返回到feign.Feign.Builder#target(feign.Target),继续看newInstance方法调用
@Override
public <T> T newInstance(Target<T> target) {
//调用targetToHandlersByName.apply,对该FeignClient中所有的方法生成 MethodHandler (SynchronousMethodHandler类型)
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
//遍历所有的 方法
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 {
//将FeignClient中方法和对应的MethodHandler 保存起来
//nameToHandler 保存的是 基于类名方法名等信息和对应的MethodHandler的集合信息
//methodToHandler保存的是method类与对应的MethodHandler的集合信息
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
//生成 handler (FeignInvocationHandler类型),含有两个属性target即 FeignClient对应的类,dispatch即类中方法和对应的MethodHandler(SynchronousMethodHandler类型)
InvocationHandler handler = factory.create(target, methodToHandler);
//基于Proxy生成JDK动态代理
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, handler);
for(DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
//返回代理对象
return proxy;
}
targetToHandlersByName.apply的调用
public Map<String, MethodHandler> apply(Target key) {
List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.type());
Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
for (MethodMetadata md : metadata) {
BuildTemplateByResolvingArgs buildTemplate;
if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder);
} else if (md.bodyIndex() != null) {
buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder);
} else {
buildTemplate = new BuildTemplateByResolvingArgs(md);
}
result.put(md.configKey(),
factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
}
return result;
}
上面我们清楚了代理中生成的 handler (FeignInvocationHandler类型),含有两个属性target即 FeignClient对应的类,dispatch即类中方法和对应的MethodHandler(SynchronousMethodHandler类型)
1、我们看下 FeignInvocationHandler的具体调用流程
feign.ReflectiveFeign.FeignInvocationHandler#invoke
@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();
}
//基于dispatch 找到对应的 MethodHandler,调用invoke方法
return dispatch.get(method).invoke(args);
}
2、我们看下 SynchronousMethodHandler的具体调用流程
@Override
public Object invoke(Object[] argv) throws Throwable {
//基于参数构建RequestTemplate
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;
}
}
}
Object executeAndDecode(RequestTemplate template) throws Throwable {
//获取Request对象
//此处也是自定义拦截器的实现
Request request = targetRequest(template);
if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}
Response response;
long start = System.nanoTime();
try {
//通过client进行发起
response = client.execute(request, options);
} catch (IOException e) {
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
}
throw errorExecuting(request, e);
}
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
boolean shouldClose = true;
try {
if (logLevel != Logger.Level.NONE) {
response =
logger.logAndRebufferResponse(metadata.configKey(), logLevel, response, elapsedTime);
}
//
if (Response.class == metadata.returnType()) {
if (response.body() == null) {
return response;
}
if (response.body().length() == null ||
response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
shouldClose = false;
return response;
}
// Ensure the response body is disconnected
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
return Response.create(response.status(), response.reason(), response.headers(), bodyData);
}
//成功进行解码返回
if (response.status() >= 200 && response.status() < 300) {
if (void.class == metadata.returnType()) {
return null;
} else {
return decode(response);
}
} else if (decode404 && response.status() == 404) {
return decoder.decode(response, metadata.returnType());
} else {
throw errorDecoder.decode(metadata.configKey(), response);
}
} catch (IOException e) {
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime);
}
throw errorReading(request, response, e);
} finally {
if (shouldClose) {
//响应流关闭
ensureClosed(response.body());
}
}
}
关于一些核心的类的定义可以查看链接来学习
操作实例可查看feign自定义请求拦截器、编码器、解码器
OpenFeign拦截器RequestInterceptor的使用