return factoryBean.getObject();
});
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
definition.setLazyInit(true);
validate(attributes);
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
beanDefinition.setAttribute(“feignClientsRegistrarFactoryBean”, factoryBean);
// has a default, won’t be null
boolean primary = (Boolean) attributes.get(“primary”);
beanDefinition.setPrimary(primary);
String[] qualifiers = getQualifiers(attributes);
if (ObjectUtils.isEmpty(qualifiers)) {
qualifiers = new String[] { contextId + “FeignClient” };
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
// 3.注入到IOC容器中
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
复制代码
3.4 注入FeignClientFactoryBean
当我们调用远程服务接口时,往往需要通过@Autowired
注解的方式注入服务,然后调用对应的方法
@RestController
public class OpenfeignConsumerController {
@Autowired
private IndexClient indexClient;
@GetMapping(“/index/{name}”)
public String index(@PathVariable(name = “name”) String name) {
return indexClient.index(name);
}
}
@FeignClient(value = “openfeign-provider-service”)
public interface IndexClient {
@GetMapping(“/index/{name}”)
String index(@PathVariable(name = “name”) String name);
}
复制代码
IndexClient
被@FeignClient
注解标注,根据3.3
章节可以了解到其实际上是一个FeignClientFactoryBean
FeignClientFactoryBean
实现了FactoryBean
接口,因此当使用@Autowired
注解进行注入的时候,注入的是FeignClientFactoryBean
中getObject()
方法返回的对象
3.5 FeignContext
从命名可以得知FeignContext
是feign
的上下文,其存在着一个Map
类型的context
属性
private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();
复制代码
也就是说,每个
@FeignClient
对应一个AnnotationConfigApplicationContext
上下文,本身应用也存在这一个AnnotationConfigApplicationContext
因此就形成了父子上下文
3.6 构建Feign Builder
Builder builder = this.feign(context);
复制代码
protected Builder feign(FeignContext context) {
FeignLoggerFactory loggerFactory = (FeignLoggerFactory)this.get(context, FeignLoggerFactory.class);
Logger logger = loggerFactory.create(this.type);
Builder builder = ((Builder)this.get(context, Builder.class)).logger(logger).encoder((Encoder)this.get(context, Encoder.class)).decoder((Decoder)this.get(context, Decoder.class)).contract((Contract)this.get(context, Contract.class));
this.configureFeign(context, builder);
this.applyBuildCustomizers(context, builder);
return builder;
}
复制代码
构建
Feign Builder
就是从容器中获取相关组件进行设置,然后在对Feign Builder
进行个性化配置
3.7 从容器获取组件
3.6
章节中this.get(context, xxxx.class))
这个方法频繁出现,需要了解一下该方法具体实现,此处以this.get(context, FeignLoggerFactory.class)
为例
protected T get(FeignContext context, Class type) {
T instance = context.getInstance(this.contextId, type);
if (instance == null) {
throw new IllegalStateException("No bean found of type " + type + " for " + this.contextId);
} else {
return instance;
}
}
复制代码
在
3.5
章节中介绍过FeignContext
,其维护了一个子容器集合,因此首先会先从子容器集合中获取指定名称的子容器
既然FeignContext
维护了子容器集合,那么就必须了解子容器是如何创建的
protected AnnotationConfigApplicationContext getContext(String name) {
if (!this.contexts.containsKey(name)) {
synchronized (this.contexts) {
if (!this.contexts.containsKey(name)) {
this.contexts.put(name, createContext(name));
}
}
}
return this.contexts.get(name);
}
protected AnnotationConfigApplicationContext createContext(String name) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
if (this.configurations.containsKey(name)) {
for (Class<?> configuration : this.configurations.get(name).getConfiguration()) {
context.register(configuration);
}
}
for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
if (entry.getKey().startsWith(“default.”)) {
for (Class<?> configuration : entry.getValue().getConfiguration()) {
context.register(configuration);
}
}
}
context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType);
context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(this.propertySourceName,
Collections.<String, Object>singletonMap(this.propertyName, name)));
if (this.parent != null) {
// Uses Environment from parent as well as beans
context.setParent(this.parent);
// jdk11 issue
// https://github.com/spring-cloud/spring-cloud-netflix/issues/3101
context.setClassLoader(this.parent.getClassLoader());
}
context.setDisplayName(generateDisplayName(name));
context.refresh();
return context;
}
复制代码
每次先从集合中取,如果集合中没有对应的子容器则进行创建,然后让容器中注册了
PropertyPlaceholderAutoConfiguration
和this.defaultConfigType
通过
FeignContext
的构造函数,我们可以了解到this.defaultConfigType
就是FeignClientsConfiguration
打开
FeignClientsConfiguration
可以看到里面声明了Encoder
、Decoder
、Contract
等Bean
3.8 小结
到这里脑海中应该有个大概的总结:
-
@FeignClient
对应FeignClientFactoryBean
-
注入
@FeignClient
标注的接口,实际上注入的是FeignClientFactoryBean
中getObject()
返回的对象 -
FeignContext
做为feign
的上下文,为每个@FeignClient
创建一个子容器,子容器中声明所需要的Bean
-
之所以为每个
@FeignClient
声明一个子容器,是会了让@FeignClient
与@FeignClient
的配置进行隔离
3.9 创建Feign实例
之前通过Feign Builder
链式方式设置了相关属性,现在就可以通过Feign Builder
来创建Feign
实例
public Feign build() {
Client client = Capability.enrich(this.client, capabilities);
Retryer retryer = Capability.enrich(this.retryer, capabilities);
List requestInterceptors = this.requestInterceptors.stream()
.map(ri -> Capability.enrich(ri, capabilities))
.collect(Collectors.toList());
Logger logger = Capability.enrich(this.logger, capabilities);
Contract contract = Capability.enrich(this.contract, capabilities);
Options options = Capability.enrich(this.options, capabilities);
Encoder encoder = Capability.enrich(this.encoder, capabilities);
Decoder decoder = Capability.enrich(this.decoder, capabilities);
// 1.InvocationHandlerFactory用于创建InvocationHandler
InvocationHandlerFactory invocationHandlerFactory =
Capability.enrich(this.invocationHandlerFactory, capabilities);
QueryMapEncoder queryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities);
// 2.SynchronousMethodHandler用于创建SynchronousMethodHandler
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404, closeAfterDecode, propagationPolicy, forceDecoding);
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
复制代码
3.10 创建代理
@Override
public T newInstance(Target target) {
// 1.遍历@FeignClient标注接口中的方法,通过SynchronousMethodHandler.Factory创建 MethodHandler
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
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 {
// 2. 构建Method与MethodHandler的映射关系,用于方法路由
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
// 3. 通过InvocationHandlerFactory创建InvocationHandler
InvocationHandler handler = factory.create(target, methodToHandler);
// 4. 生成代理对象
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
new Class<?>[] {target.type()}, handler);
for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
复制代码
到此我们可以得知
@Autowired
private IndexClient indexClient;
复制代码
注入的是一个代理对象,当调用
IndexClient
方法的时候,会回调ReflectiveFeign.FeignInvocationHandler
的invoke
方法
3.11 方法调用
@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);
}
复制代码
如上根据方法路由到对应的
SynchronousMethodHandler
,然后调用其invoke()
@Override
public Object invoke(Object[] argv) throws Throwable {
// 1.构建请求模板
RequestTemplate template = buildTemplateFromArgs.create(argv);
Options options = findOptions(argv);
Retryer retryer = this.retryer.clone();
while (true) {
try {
// 2.通过http方式发起远程调用并返回结果
return executeAndDecode(template, options);
} catch (RetryableException e) {
try {
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
Throwable cause = th.getCause();
if (propagationPolicy == UNWRAP && cause != null) {
throw cause;
} else {
throw th;
}
}
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}