在分析源码前,还是先介绍一下简单的使用流程。
首先引入依赖
org.springframework.cloud spring-cloud-starter-openfeign
开启自动Feign客户端功能
@SpringBootApplication //可以配置扫描的Feign客户端包路径,不配置则为TestApplication.class包下 @EnableFeignClients public class TestApplication { public static void main(String[] args) { SpringApplication.run(FeignApplication.class); } }
定义FeignClient
//可以添加一些配置,例如服务名,url之类 @FeignClient public interface TestFeignClient{ //Spring MVC,调用地址要和服务提供方一致 @RequestMapping public String geta(); }
openfeign的基本使用就是这样,然后加上自己所需要的配置即可。接下来就开始分析openfeign是如何开启,并如何实现远程调用的原理。
@EnableFeignClients开启Feign功能@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @documented //FeignClients注册器 @import(FeignClientsRegistrar.class) public @interface EnableFeignClients { //注解的配置 //...... } //实现了importBeanDefinitionRegistrar接口,去看registerBeanDefinitions()方法 class FeignClientsRegistrar implements importBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware
#FeignClientsRegistrar public void registerBeanDefinitions(Annotationmetadata metadata, BeanDefinitionRegistry registry) { //注册@EnableFeignClients上定义的defaultConfiguration默认配置类 registerDefaultConfiguration(metadata, registry); //扫描所有的@FeignClient注解 registerFeignClients(metadata, registry); }注册默认配置类
#FeignClientsRegistrar private void registerDefaultConfiguration(Annotationmetadata metadata, BeanDefinitionRegistry registry) { //获取@EnableFeignClients配置的信息 Map扫描@FeignClient注解defaultAttrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName(), true); //判断是否配置了defaultConfiguration if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) { String name; //判断配置在defaultConfiguration是否为内部类,拼接对应的类名 if (metadata.hasEnclosingClass()) { name = "default." + metadata.getEnclosingClassName(); } else { name = "default." + metadata.getClassName(); } //跟进去 registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration")); } } #FeignClientsRegistrar private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) { BeanDefinitionBuilder builder = BeanDefinitionBuilder .genericBeanDefinition(FeignClientSpecification.class); builder.addConstructorArgValue(name); builder.addConstructorArgValue(configuration); //将@EnableFeignClients中的配置信息注册到容器中 registry.registerBeanDefinition( name + "." + FeignClientSpecification.class.getSimpleName(), builder.getBeanDefinition()); }
#FeignClientsRegistrar public void registerFeignClients(Annotationmetadata metadata, BeanDefinitionRegistry registry) { //获取类路径扫描器 ClassPathScanningCandidateComponentProvider scanner = getScanner(); //设置资源加载器 scanner.setResourceLoader(this.resourceLoader); SetbasePackages; //获取@EnableFeignClients的注解信息 Map attrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName()); //创建@FeignClient类型的过滤器 AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter( FeignClient.class); final Class>[] clients = attrs == null ? null : (Class>[]) attrs.get("clients"); if (clients == null || clients.length == 0) { scanner.addIncludeFilter(annotationTypeFilter); //获取包路径 basePackages = getbasePackages(metadata); } else { //...... } //遍历包路径 for (String basePackage : basePackages) { //获取该包路径下带@FeignClient的BD信息 Set candidateComponents = scanner .findCandidateComponents(basePackage); for (BeanDefinition candidateComponent : candidateComponents) { if (candidateComponent instanceof AnnotatedBeanDefinition) { AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent; Annotationmetadata annotationmetadata = beanDefinition.getmetadata(); Assert.isTrue(annotationmetadata.isInterface(), "@FeignClient can only be specified on an interface"); //获取@FeignClient的注解信息 Map attributes = annotationmetadata .getAnnotationAttributes( FeignClient.class.getCanonicalName()); //获取@FeignClient上配置的名称,优先级为contextId>value>name>serviceId String name = getClientName(attributes); //注册@FeignClient的配置信息 registerClientConfiguration(registry, name, attributes.get("configuration")); //注册加了@FeignClient的类到容器中 registerFeignClient(registry, annotationmetadata, attributes); } } } } #FeignClientsRegistrar private void registerFeignClient(BeanDefinitionRegistry registry, Annotationmetadata annotationmetadata, Map attributes) { //返回添加了@FeignClient注解的Class的全限定名, 包名.类名 String className = annotationmetadata.getClassName(); //FeignClientFactoryBean是一个FactoryBean,用它来创建具体的FeignClient BeanDefinitionBuilder definition = BeanDefinitionBuilder .genericBeanDefinition(FeignClientFactoryBean.class); validate(attributes); //向FeignClientFactoryBean添加@FeignClient中配置的一些注解信息 definition.addPropertyValue("url", getUrl(attributes)); definition.addPropertyValue("path", getPath(attributes)); String name = getName(attributes); definition.addPropertyValue("name", name); String contextId = getContextId(attributes); definition.addPropertyValue("contextId", contextId); definition.addPropertyValue("type", className); definition.addPropertyValue("decode404", attributes.get("decode404")); definition.addPropertyValue("fallback", attributes.get("fallback")); definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory")); definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); String alias = contextId + "FeignClient"; AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); boolean primary = (Boolean) attributes.get("primary"); beanDefinition.setPrimary(primary); String qualifier = getQualifier(attributes); if (StringUtils.hasText(qualifier)) { alias = qualifier; } BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] { alias }); //将FeignClientFactoryBean注册到容器中 BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); }
这一步完成后,所有的加了@FeignClient的类就会被解析成FeignClientFactoryBean类型的BeanDefinition加入到容器中,FeignClientFactoryBean包含了@FeignClient上配置的信息,以及保存了当前添加@FeignClient注解的Class名称。之后就是Spring容器在refresh()内会去实例化该FeignClient,而FeignClientFactoryBean是FactoryBean类型,所以会调用它的getObject()进行实例化。
FeignClient实例化#FeignClientFactoryBean public Object getObject() throws Exception { return getTarget(); } #FeignClientFactoryBeanT getTarget() { //获取FeignContext,在FeignAutoConfiguration自动装配进来 FeignContext context = this.applicationContext.getBean(FeignContext.class); //创建builder对象,用来生成Feign Feign.Builder builder = feign(context); //如果没有在@FeignClient配置了url,说明要负载均衡 if (!StringUtils.hasText(this.url)) { //构造url if (!this.name.startsWith("http")) { this.url = "http://" + this.name; } else { this.url = this.name; } //http://服务名 this.url += cleanPath(); //创建负载均衡代理类 return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type, this.name, this.url)); } //说明url存在,使用硬编码的方式 if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) { //直接拼接url this.url = "http://" + this.url; } String url = this.url + cleanPath(); //获取客户端对象 Client client = getOptional(context, Client.class); if (client != null) { //Ribbon客户端对象LoadBalancerFeignClient if (client instanceof LoadBalancerFeignClient) { client = ((LoadBalancerFeignClient) client).getDelegate(); } builder.client(client); } //在FeignAutoConfiguration自动装配进来 Targeter targeter = get(context, Targeter.class); //生成动态代理对象 return (T) targeter.target(this, builder, context, new HardCodedTarget<>(this.type, this.name, url)); }
先来看看FeignAutoConfiguration都装配了什么Bean
FeignAutoConfiguration自动装配@Configuration @ConditionalOnClass(Feign.class) @EnableConfigurationProperties({ FeignClientProperties.class, FeignHttpClientProperties.class }) public class FeignAutoConfiguration { //FeignContext,内部保存了创建FeignClient所需的组件 @Bean public FeignContext feignContext() { FeignContext context = new FeignContext(); context.setConfigurations(this.configurations); return context; } //以下是两个相对的条件 @Configuration @ConditionalOnClass(name = "feign.hystrix.HystrixFeign")//引入hystrix protected static class HystrixFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { //创建Hystrix类型 return new HystrixTargeter(); } } @Configuration @ConditionalOnMissingClass("feign.hystrix.HystrixFeign")//未引入hystrix protected static class DefaultFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { //创建默认类型 return new DefaultTargeter(); } } //下面还有HttpClient,Okhttp的配置 }
FeignAutoConfiguration配置类会自动装配一些用来创建FeignClient实例的Bean信息。
创建生成Feign的Builder对象#FeignClientFactoryBean protected Feign.Builder feign(FeignContext context) { FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class); Logger logger = loggerFactory.create(this.type); //设置Logger、Encoder、Decoder等组件 Feign.Builder builder = get(context, Feign.Builder.class) .logger(logger) .encoder(get(context, Encoder.class)) .decoder(get(context, Decoder.class)) .contract(get(context, Contract.class)); //配置builder configureFeign(context, builder); return builder; } #FeignClientFactoryBean protected void configureFeign(FeignContext context, Feign.Builder builder) { FeignClientProperties properties = this.applicationContext .getBean(FeignClientProperties.class); //从.properties配置文件中加载配置 if (properties != null) { if (properties.isDefaultToProperties()) { configureUsingConfiguration(context, builder); configureUsingProperties( properties.getConfig().get(properties.getDefaultConfig()), builder); configureUsingProperties(properties.getConfig().get(this.contextId), builder); } else { configureUsingProperties( properties.getConfig().get(properties.getDefaultConfig()), builder); configureUsingProperties(properties.getConfig().get(this.contextId), builder); configureUsingConfiguration(context, builder); } } //配置类@Bean加载配置 else { configureUsingConfiguration(context, builder); } }
在加载配置到builder对象中后,就是去生成代理对象的逻辑。
创建Feign代理对象首先来看看创建负载均衡代理对象
#FeignClientFactoryBean protectedT loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget target) { //获取客户端对象 Client client = getOptional(context, Client.class); if (client != null) { builder.client(client); //获取Targeter,分别有HystrixTargeter和DefaultTargeter类型 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-netflix-ribbon?"); }
先分析DefaultTargeter类型的代理对象
DefaultTargeter创建代理对象#DefaultTargeter publicT target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget target) { return feign.target(target); } #Feign public T target(Target target) { //跟进去 return build().newInstance(target); } #Feign.Builder public Feign build() { //构建SynchronousMethodHandler工厂 SynchronousMethodHandler.Factory synchronousMethodHandlerFactory = new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger, logLevel, decode404, closeAfterDecode, propagationPolicy); //设置组件对象 ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder, errorDecoder, synchronousMethodHandlerFactory); //创建ReflectiveFeign实例,invocationHandlerFactory是InvocationHandlerFactory.Default类型 return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder); } #ReflectiveFeign 是Feign的实现类 public T newInstance(Target target) { //target内部保存了当前加了@FeignClient的接口Class,apply()会解析出接口中的方法和方法上的注解 //key是方法名,value是SynchronousMethodHandler类型,内部持有这个方法和注解的所有信息 Map nameToHandler = targetToHandlersByName.apply(target); Map methodToHandler = new linkedHashMap (); List defaultMethodHandlers = new linkedList (); //target.type()就是获取接口的Class //遍历所有的接口方法 for (Method method : target.type().getMethods()) { if (method.getDeclaringClass() == Object.class) { //Object的方法不管 continue; } else if (Util.isDefault(method)) { //default 类型的方法,要加入到defaultMethodHandlers集合 DefaultMethodHandler handler = new DefaultMethodHandler(method); defaultMethodHandlers.add(handler); methodToHandler.put(method, handler); } else { //非Object,default的方法,从nameToHandler中取出添加到methodToHandler集合 methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method))); } } //InvocationHandler工厂创建InvocationHandler对象 InvocationHandler handler = factory.create(target, methodToHandler); //创建代理对象 T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class>[] {target.type()}, handler); for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) { //将default方法绑定在代理对象上 defaultMethodHandler.bindTo(proxy); } //返回代理对象 return proxy; }
到这里代理对象也创建完成了,接下来就该去看看InvocationHandler的invoke方法是在哪实现的。
InvocationHandler对象调用invoke()#InvocationHandlerFactory.Default public InvocationHandler create(Target target, MapDefaultMethodHandler的invoke()dispatch) { //创建了FeignInvocationHandler类型的InvocationHandler,直接看它的invoke方法 return new ReflectiveFeign.FeignInvocationHandler(target, dispatch); } #FeignInvocationHandler 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(); } //dispatch就是在构造中赋值的,在#ReflectiveFeign的newInstance()方法中的methodToHandler //key为接口中的方法,value为SynchronousMethodHandler和DefaultMethodHandler类型 //所以接下来就去看这两个类型的invoke方法 return dispatch.get(method).invoke(args); }
public Object invoke(Object[] argv) throws Throwable { if (handle == null) { throw new IllegalStateException( "Default method handler invoked before proxy has been bound."); } //default修饰的方法就直接执行 return handle.invokeWithArguments(argv); }SynchronousMethodHandler的invoke()
public Object invoke(Object[] argv) throws Throwable { //将方法参数构建成RequestTemplate,这个对象相信大家都很熟悉 RequestTemplate template = buildTemplateFromArgs.create(argv); Options options = findOptions(argv); Retryer retryer = this.retryer.clone(); while (true) { try { //执行请求 return executeAndDecode(template, options); } catch (RetryableException e) { try { //重试机制 retryer.continueOrPropagate(e); } //...... } } } #SynchronousMethodHandler Object executeAndDecode(RequestTemplate template, Options options) throws Throwable { //调用RequestInterceptor,根据template生成Request对象 Request request = targetRequest(template); //...... //响应对象 Response response; long start = System.nanoTime(); try { //调用客户端的execute执行请求 response = client.execute(request, options); } catch (IOException e) { //...... } long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start); boolean shouldClose = true; try { //...... //对response进行解码 if (Response.class == metadata.returnType()) { if (response.body() == null) { return response; } if (response.body().length() == null || response.body().length() > MAX_RESPONSE_BUFFER_SIZE) { shouldClose = false; return response; } byte[] bodyData = Util.toByteArray(response.body().asInputStream()); return response.toBuilder().body(bodyData).build(); } if (response.status() >= 200 && response.status() < 300) { if (void.class == metadata.returnType()) { return null; } else { Object result = decode(response); shouldClose = closeAfterDecode; return result; } } else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) { Object result = decode(response); shouldClose = closeAfterDecode; return result; } else { throw errorDecoder.decode(metadata.configKey(), response); } } //...... }
真正执行请求的client.execute(request, options)是一个接口方法,是由不同的客户端工具进行实现。如果没有导入Ribbon,那么就用feign自带的Client.Default内部进行实现。Client是一个接口。
#Client.Default public Response execute(Request request, Options options) throws IOException { //convertAndSend()发送请求 HttpURLConnection connection = convertAndSend(request, options); //convertResponse()响应解码 return convertResponse(connection, request); }
如果导入了Ribbon,那么就是LoadBalancerFeignClient实现,内部使用Ribbon进行负载均衡
#LoadBalancerFeignClient public Response execute(Request request, Request.Options options) throws IOException { try { URI asUri = URI.create(request.url()); String clientName = asUri.getHost(); URI uriWithoutHost = cleanUrl(request.url(), clientName); FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest( this.delegate, request, uriWithoutHost); IClientConfig requestConfig = getClientConfig(options, clientName); return lbClient(clientName) .executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse(); } //...... }
到这里,没有导入Hystrix创建代理对象的流程就分析完了,一些具体解析的方法并没有去详细分析,因为我们主要是理解openfeign的执行流程,所以分析创建代理对象,然后到真正执行请求的地方就行了。接下来是去分析引入了Hystrix后是如何创建代理。
HystrixTargeter创建代理对象#HystrixTargeter publicT target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget target) { //判断是否为HystrixFeign类型 if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) { //这里会调用ReflectiveFeign的那段逻辑 return feign.target(target); } feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign; String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName() : factory.getContextId(); SetterFactory setterFactory = getOptional(name, context, SetterFactory.class); if (setterFactory != null) { builder.setterFactory(setterFactory); } //是否设置降级 Class> fallback = factory.getFallback(); if (fallback != void.class) { return targetWithFallback(name, context, target, builder, fallback); } Class> fallbackFactory = factory.getFallbackFactory(); if (fallbackFactory != void.class) { return targetWithFallbackFactory(name, context, target, builder, fallbackFactory); } //执行到这说明没有设置降级,又会回到ReflectiveFeign return feign.target(target); }
虽然导入了Hystrix,但是内部还是会判断是否设置过降级,如果没有,会回到普通的调用链路。上面的降级分支最终都会合并到一起,所以分析一个方法就行。
#HystrixTargeter privateT targetWithFallback(String feignClientName, FeignContext context, Target.HardCodedTarget target, HystrixFeign.Builder builder, Class> fallback) { T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type()); //创建代理对象,跟进去 return builder.target(target, fallbackInstance); } #HystrixFeign.Builder public T target(Target target, T fallback) { //newInstance会回到ReflectiveFeign逻辑,我们关心的是引入hystrix后,InvocationHandler的类型 //在build中会设置InvocationHandlerFactory的类型 return build(fallback != null ? new FallbackFactory.Default (fallback) : null) .newInstance(target); } #HystrixFeign.Builder Feign build(final FallbackFactory> nullableFallbackFactory) { super.invocationHandlerFactory(new InvocationHandlerFactory() { @Override public InvocationHandler create(Target target, Map dispatch) { //最终返回了HystrixInvocationHandler实例,所以去看它的invoke方法 return new HystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory); } }); super.contract(new HystrixDelegatingContract(contract)); return super.build(); } #HystrixInvocationHandler public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { //...... HystrixCommand
到这里Hystrix的代理逻辑也分析完了,它和默认创建代理对象的逻辑就是invoke()的实现不同,它只是对请求加了熔断降级的处理,其他的流程基本一致。
以上就是openfeign源码分析的整体流程,首先从feign的功能是如何开启的开始分析,然后到FeignClient是如何添加到容器当中,接着分析FeignClient是如何被代理创建,最后分析了默认方式和引入Hystrix的方式分别是如何执行的。总的来说,如果只是理解openfeign的大概执行流程,了解这么多已经足够了,但还想知道一些对象具体是如何解析创建出来、请求响应是如何执行的,那请大家自行研究。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)