在Spring-Cloud-OpenFeign源码解析-02-OpenFeign自动装配分析到OpenFeign
接口代理对象的创建是通过构建成一个 FeignClientFactoryBean
对象,并最后注入到容器中的,那么这个FeignClientFactoryBean
是如何实现代理对象创建的呢?
FactoryBean
public interface FactoryBean<T> {String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";@NullableT getObject() throws Exception;@NullableClass<?> getObjectType();default boolean isSingleton() {return true;}
FactoryBean
是Spring框架中的一个扩展接口,用于创建和管理其他Bean实例的对象。使用它可以生成某些需要复杂初始化过程的bean对象。当配置某个bean实现了FactoryBean
接口时,该bean返回的对象不是FactoryBean
本身,而是FactoryBean#getObject()
方法返回的对象,这就提供了我们自定义创建对象的能力。
它与Spring其他bean的主要区别在于,FactoryBean
负责产生其他bean实例。也即当我们从IOC容器中获取一个FactoryBean
时,我们得到的是它创建的那个bean的实例,而不是FactoryBean
的实例本身。
FeignClientFactoryBean
public class FeignClientFactoryBeanimplements FactoryBean<Object>, InitializingBean, ApplicationContextAware, BeanFactoryAware {@Overridepublic Object getObject() {//调用getTarget()方法return getTarget();}/*** @param <T> the target type of the Feign client* @return a {@link Feign} client created with the specified data and the context* information*/<T> T getTarget() {FeignContext context = beanFactory != null ? beanFactory.getBean(FeignContext.class): applicationContext.getBean(FeignContext.class);Feign.Builder builder = feign(context);// 判断当前FeignClient注解中的url是否为空,如果不为空,直接通过url的调用if (!StringUtils.hasText(url)) {if (LOG.isInfoEnabled()) {LOG.info("For '" + name + "' URL not provided. Will try picking an instance via load-balancing.");}//是否以http开头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 FeignBlockingLoadBalancerClient) {// not load balancing because we have a url,// but Spring Cloud LoadBalancer is on the classpath, so unwrapclient = ((FeignBlockingLoadBalancerClient) client).getDelegate();}if (client instanceof RetryableFeignBlockingLoadBalancerClient) {// not load balancing because we have a url,// but Spring Cloud LoadBalancer is on the classpath, so unwrapclient = ((RetryableFeignBlockingLoadBalancerClient) client).getDelegate();}builder.client(client);}applyBuildCustomizers(context, builder);Targeter targeter = get(context, Targeter.class);//返回目标对象return (T) targeter.target(this, builder, context, new HardCodedTarget<>(type, name, url));}
}protected <T> T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget<T> target) {Client client = getOptional(context, Client.class);if (client != null) {builder.client(client);applyBuildCustomizers(context, builder);Targeter targeter = get(context, Targeter.class);//返回目标对象return targeter.target(this, builder, context, target);}throw new IllegalStateException("No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?");}
最终都会调用到targeter.target()
方法
Targeter#target()
默认调用的是DefaultTargeter
class DefaultTargeter implements Targeter {@Overridepublic <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,Target.HardCodedTarget<T> target) {//继续调用target方法return feign.target(target);}
}
feign.target()
public abstract class Feign {public <T> T target(Target<T> target) {//创建代理对象return build().newInstance(target);}//构建Feign对象public Feign build() {Client client = Capability.enrich(this.client, capabilities);Retryer retryer = Capability.enrich(this.retryer, capabilities);List<RequestInterceptor> 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);//创建代理对象的InvocationHandler工厂实例InvocationHandlerFactory invocationHandlerFactory =Capability.enrich(this.invocationHandlerFactory, capabilities);QueryMapEncoder queryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities);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);//最终返回ReflectiveFeign实例return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);}
}
ReflectiveFeign.newInstance()
public class ReflectiveFeign extends Feign {@Overridepublic <T> T newInstance(Target<T> target) {Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();//解析方法,封装为MethodHandlerfor (Method method : target.type().getMethods()) {//Object方法if (method.getDeclaringClass() == Object.class) {continue;//Default方法} 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);//jdk动态代理创建对象T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),new Class<?>[] {target.type()}, handler);for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {defaultMethodHandler.bindTo(proxy);}//返回代理对象return proxy;}
}
总结
通过创建FeignClientFactoryBean
对象,在@Autowired
或者@Resource
注入FeignClient
实例的时候,实际上返回的是FactoryBean#getObject()
方法创建的对象,底层通过JDK动态代理Proxy.newProxyInstance()
返回代理对象,具体的实现逻辑在InvocationHandler
的invoke方法中