spring cloud openfeign 源码
Posted 挎木剑的游侠儿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring cloud openfeign 源码相关的知识,希望对你有一定的参考价值。
一、读取注解信息
入口
1 import org.springframework.boot.SpringApplication; 2 import org.springframework.boot.autoconfigure.SpringBootApplication; 3 import org.springframework.cloud.openfeign.EnableFeignClients; 4 5 6 @SpringBootApplication 7 @EnableFeignClients 8 public class CjsPriceServiceApplication { 9 10 public static void main(String[] args) { 11 SpringApplication.run(CjsPriceServiceApplication.class, args); 12 } 13 14 }
spring boot 项目启动后会自动扫描application上面的注解,@EnableFeignClients的注解如下
1 @Retention(RetentionPolicy.RUNTIME) 2 @Target(ElementType.TYPE) 3 @Documented 4 @Import(FeignClientsRegistrar.class) 5 public @interface EnableFeignClients { 6 。。。。 7 }
在注解中导入了 FeignClientsRegistrar类,用来像spring注册,EnableFeignClients和FeignClient上面开发人员添加的注解信息
1 @Override 2 public void registerBeanDefinitions(AnnotationMetadata metadata, 3 BeanDefinitionRegistry registry) { 4 registerDefaultConfiguration(metadata, registry); 5 registerFeignClients(metadata, registry); 6 }
二、当项目启动,读取@Autowired时会调用,实现了FactoryBean接口的FeignClientFactoryBean.getObject()方法
1 @Override 2 public Object getObject() throws Exception { 3 return getTarget(); 4 }
1 <T> T getTarget() { 2 FeignContext context = this.applicationContext.getBean(FeignContext.class); 3 Feign.Builder builder = feign(context); 4 5 if (!StringUtils.hasText(this.url)) { 6 if (!this.name.startsWith("http")) { 7 this.url = "http://" + this.name; 8 } 9 else { 10 this.url = this.name; 11 } 12 this.url += cleanPath(); 13 return (T) loadBalance(builder, context, 14 new HardCodedTarget<>(this.type, this.name, this.url)); 15 } 16 if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) { 17 this.url = "http://" + this.url; 18 } 19 String url = this.url + cleanPath(); 20 Client client = getOptional(context, Client.class); 21 if (client != null) { 22 if (client instanceof LoadBalancerFeignClient) { 23 // not load balancing because we have a url, 24 // but ribbon is on the classpath, so unwrap 25 client = ((LoadBalancerFeignClient) client).getDelegate(); 26 } 27 builder.client(client); 28 } 29 Targeter targeter = get(context, Targeter.class); 30 return (T) targeter.target(this, builder, context, 31 new HardCodedTarget<>(this.type, this.name, url)); 32 }
可以看到 getTarget()有两种返回结果的情况,其原理都一样后来调用了 targeter.target()方法
1 package org.springframework.cloud.openfeign; 2 3 import feign.Feign; 4 import feign.Target; 5 6 /** 7 * @author Spencer Gibb 8 */ 9 interface Targeter { 10 11 <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, 12 FeignContext context, Target.HardCodedTarget<T> target); 13 14 }
默认实现类
1 package org.springframework.cloud.openfeign; 2 3 import feign.Feign; 4 import feign.Target; 5 6 /** 7 * @author Spencer Gibb 8 */ 9 class DefaultTargeter implements Targeter { 10 11 @Override 12 public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, 13 FeignContext context, Target.HardCodedTarget<T> target) { 14 return feign.target(target); 15 } 16 17 }
然后再看 feign.target(target);方法
1 public <T> T target(Target<T> target) { 2 return build().newInstance(target); 3 } 4 5 public Feign build() { 6 SynchronousMethodHandler.Factory synchronousMethodHandlerFactory = 7 new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger, 8 logLevel, decode404, closeAfterDecode, propagationPolicy); 9 ParseHandlersByName handlersByName = 10 new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder, 11 errorDecoder, synchronousMethodHandlerFactory); 12 return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder); 13 } 14 }
build()方法返回了创建代理类的对象,然后调用了创建代理的 newInstance方法
1 public <T> T newInstance(Target<T> target) { 2 Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target); 3 Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>(); 4 List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>(); 5 6 for (Method method : target.type().getMethods()) { 7 if (method.getDeclaringClass() == Object.class) { 8 continue; 9 } else if (Util.isDefault(method)) { 10 DefaultMethodHandler handler = new DefaultMethodHandler(method); 11 defaultMethodHandlers.add(handler); 12 methodToHandler.put(method, handler); 13 } else { 14 methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method))); 15 } 16 } 17 InvocationHandler handler = factory.create(target, methodToHandler); 18 T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), 19 new Class<?>[] {target.type()}, handler); 20 21 for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) { 22 defaultMethodHandler.bindTo(proxy); 23 } 24 return proxy; 25 }
最后,当我们项目中使用 @Autowired注入时,就回调用工厂类 FeignClientFactoryBean方法的 getObject()方法 返回我们的代理对象
以上是关于spring cloud openfeign 源码的主要内容,如果未能解决你的问题,请参考以下文章
Feign 系列(05)Spring Cloud OpenFeign 源码解析