Open Feign(伪声明式RPC) 之所以称之为伪RPC,是因为它几乎和PRC的调用过程一样,像序列化,反序列化,动态代理之类的流程都有
面向接口的一种代理的封装,
思考Feign要做到的事情
参数的解析与装载
针对制定的feignClient,生成动态代理
针对FeignClient中的方法描述进行解析
组装出一个Request对象,发起请求
首先从@EnableFeignClients()注解进入@Import({FeignClientsRegistrar.class});
FeignClientsRegistrar类实现了ImportBeanDefinitionRegistrar接口;动态的将Bean装载到IOC容器中;
FeignClientsRegistrar类调用registerFeignClients();对于配置的package中可以能有多个FeignClient,用双重循环遍历不同路径下的不同的FeignClients和配置;
接着进入registerFeignClient()方法中;FeignClient被动态注册成一个FactoryBean
FactoryBean有一个特征,就是如果需要获得这个Bean的真正实例,会通过
FeignClientFactoryBean.getObject()中getTarget来获取最终实例,getTarget中会根据是否有URL,如果没有执行LoadBalancer负载均衡,否则进入下一个流程。
进入LoadBalancer方法的解析,其中有三个参数,FeignContext是代表Feign的上下文信息,
protected <T> T loadBalance(Builder builder, FeignContext context, HardCodedTarget<T> target) { Client client = (Client)this.getOptional(context, Client.class); //获取特定的实例的客户端 if (client != null) { builder.client(client); //增加了请求的负载均衡的解析机制 Targeter targeter = (Targeter)this.get(context, Targeter.class); return targeter.target(this, builder, context, target); //target会有多种实现 } else { throw new IllegalStateException("No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?"); } }
target有多种实现?
FeignAutoConfiguration自动装配类,自动装载FeignAutoConfigure.
Builder:
Client client = (Client)this.getOptional(context, Client.class);
getOptional通过获取FeignContext.getInstance(this.contextId, type); 针对某一个特定实例的上下文
builder.client(client);