你必须懂也可以懂的微服务系列三:服务调用

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注解进行注入的时候,注入的是FeignClientFactoryBeangetObject()方法返回的对象

3.5 FeignContext

从命名可以得知FeignContextfeign的上下文,其存在着一个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;

}

复制代码

每次先从集合中取,如果集合中没有对应的子容器则进行创建,然后让容器中注册了PropertyPlaceholderAutoConfigurationthis.defaultConfigType

通过FeignContext的构造函数,我们可以了解到this.defaultConfigType就是FeignClientsConfiguration

打开FeignClientsConfiguration可以看到里面声明了EncoderDecoderContractBean

3.8 小结

到这里脑海中应该有个大概的总结:

  • @FeignClient对应FeignClientFactoryBean

  • 注入@FeignClient标注的接口,实际上注入的是FeignClientFactoryBeangetObject()返回的对象

  • 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.FeignInvocationHandlerinvoke方法

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);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值