微服务OpenFeign源码分析

深入理解OpenFeign源码,可以深入理解接口调用转为HTTP请求、实现负载均衡工作机制,便于根据业务定制扩展功能,或者快速定位请求问题根源。另一方面,可以理解动态代理优秀设计模式,有助于提升开发者架构设计与编程能力。

01 自动装配

OpenFeign依赖spring-cloud-openfeign-core.jar配置默认行为,借助spring.factories文件实现配置发现和解析。

properties 复制代码
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.openfeign.ribbon.FeignRibbonClientAutoConfiguration,\
org.springframework.cloud.openfeign.hateoas.FeignHalAutoConfiguration,\
org.springframework.cloud.openfeign.FeignAutoConfiguration,\
org.springframework.cloud.openfeign.encoding.FeignAcceptGzipEncodingAutoConfiguration,\
org.springframework.cloud.openfeign.encoding.FeignContentGzipEncodingAutoConfiguration,\
org.springframework.cloud.openfeign.loadbalancer.FeignLoadBalancerAutoConfiguration

1.1 客户端配置

FeignAutoConfiguration用于配置Feign默认组件,默认提供Feign、FeignContext和HTTP客户端配置。

java 复制代码
@EnableConfigurationProperties({FeignClientProperties.class, FeignHttpClientProperties.class })
@Import(DefaultGzipDecoderConfiguration.class)
public class FeignAutoConfiguration {
    @Autowired(required = false)
    private List<FeignClientSpecification> configurations = new ArrayList<>();
    
    @Bean
    public FeignContext feignContext() {
        FeignContext context = new FeignContext();
        context.setConfigurations(this.configurations);
        return context;
    }
    
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnMissingClass("feign.hystrix.HystrixFeign")
    protected static class DefaultFeignTargeterConfiguration {
        @Bean
        @ConditionalOnMissingBean
        public Targeter feignTargeter() {
            return new DefaultTargeter();
        }
    }
    
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(ApacheHttpClient.class)
    @ConditionalOnMissingBean(CloseableHttpClient.class)
    @ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
    @ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
    protected static class HttpClientFeignConfiguration {
        @Autowired(required = false)
        private RegistryBuilder registryBuilder;

        private CloseableHttpClient httpClient;

        @Bean
        @ConditionalOnMissingBean(HttpClientConnectionManager.class)
        public HttpClientConnectionManager connectionManager(
            ApacheHttpClientConnectionManagerFactory connectionManagerFactory,
            FeignHttpClientProperties httpClientProperties) {
            final HttpClientConnectionManager connectionManager = connectionManagerFactory
                    .newConnectionManager(httpClientProperties.isDisableSslValidation(),
                            httpClientProperties.getMaxConnections(),
                            httpClientProperties.getMaxConnectionsPerRoute(),
                            httpClientProperties.getTimeToLive(),
                            httpClientProperties.getTimeToLiveUnit(),
                            this.registryBuilder);
            this.connectionManagerTimer.schedule(new TimerTask() {
                @Override
                public void run() {
                    connectionManager.closeExpiredConnections();
                }
            }, 30000, httpClientProperties.getConnectionTimerRepeat());
            return connectionManager;
        }

        @Bean
        public CloseableHttpClient httpClient(ApacheHttpClientFactory httpClientFactory,
                HttpClientConnectionManager httpClientConnectionManager,
                FeignHttpClientProperties httpClientProperties) {
            RequestConfig defaultRequestConfig = RequestConfig.custom()
                    .setConnectTimeout(httpClientProperties.getConnectionTimeout())
                    .setRedirectsEnabled(httpClientProperties.isFollowRedirects())
                    .build();
            this.httpClient = httpClientFactory.createBuilder()
                    .setConnectionManager(httpClientConnectionManager)
                    .setDefaultRequestConfig(defaultRequestConfig).build();
            return this.httpClient;
        }

        @Bean
        @ConditionalOnMissingBean(Client.class)
        public Client feignClient(HttpClient httpClient) {
            return new ApacheHttpClient(httpClient);
        }
    }
}

1.2 Feign上下文

FeignContext全局默认类为FeignClientsConfiguration,解析过程与Ribbon、LoadBalancer相同。

java 复制代码
public class FeignContext extends NamedContextFactory<FeignClientSpecification> {
    public FeignContext() {
        super(FeignClientsConfiguration.class, "feign", "feign.client.name");
    }

    @Nullable
    public <T> T getInstanceWithoutAncestors(String name, Class<T> type) {
        try {
            return BeanFactoryUtils.beanOfType(getContext(name), type);
        }
        catch (BeansException ex) {
            return null;
        }
    }

    @Nullable
    public <T> Map<String, T> getInstancesWithoutAncestors(String name, Class<T> type) {
        return getContext(name).getBeansOfType(type);
    }
}

1.3 全局默认配置

Feign全局默认配置类为FeignClientsConfiguration,提供编码器(Encoder)、解码器(Decoder)、锲约(Contract)、客户端代理创建(Targeter)等配置支持。

java 复制代码
@Configuration(proxyBeanMethods = false)
public class FeignClientsConfiguration {
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;
    @Autowired(required = false)
    private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>();
    @Autowired(required = false)
    private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>();
    @Autowired(required = false)
    private Logger logger;
    @Autowired(required = false)
    private SpringDataWebProperties springDataWebProperties;

    @Bean
    @ConditionalOnMissingBean
    public Decoder feignDecoder() {
        return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
    }
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnMissingClass("org.springframework.data.domain.Pageable")
    public Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) {
        return springEncoder(formWriterProvider);
    }
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnClass(name = "org.springframework.data.domain.Pageable")
    public Encoder feignEncoderPageable(ObjectProvider<AbstractFormWriter> formWriterProvider) {
        PageableSpringEncoder encoder = new PageableSpringEncoder(springEncoder(formWriterProvider));
        if (springDataWebProperties != null) {
            encoder.setPageParameter(springDataWebProperties.getPageable().getPageParameter());
            encoder.setSizeParameter(springDataWebProperties.getPageable().getSizeParameter());
            encoder.setSortParameter(springDataWebProperties.getSort().getSortParameter());
        }
        return encoder;
    }
    @Bean
    @ConditionalOnMissingBean
    public Contract feignContract(ConversionService feignConversionService) {
        return new SpringMvcContract(this.parameterProcessors, feignConversionService);
    }
    @Bean
    public FormattingConversionService feignConversionService() {
        FormattingConversionService conversionService = new DefaultFormattingConversionService();
        for (FeignFormatterRegistrar feignFormatterRegistrar : this.feignFormatterRegistrars) {
            feignFormatterRegistrar.registerFormatters(conversionService);
        }
        return conversionService;
    }
    @Bean
    @ConditionalOnMissingBean
    public Retryer feignRetryer() {
        return Retryer.NEVER_RETRY;
    }
    @Bean
    @Scope("prototype")
    @ConditionalOnMissingBean
    public Feign.Builder feignBuilder(Retryer retryer) {
        return Feign.builder().retryer(retryer);
    }
    @Bean
    @ConditionalOnMissingBean(FeignLoggerFactory.class)
    public FeignLoggerFactory feignLoggerFactory() {
        return new DefaultFeignLoggerFactory(this.logger);
    }
    @Bean
    @ConditionalOnClass(name = "org.springframework.data.domain.Page")
    public Module pageJacksonModule() {
        return new PageJacksonModule();
    }
    @Bean
    @ConditionalOnClass(name = "org.springframework.data.domain.Page")
    public Module sortModule() {
        return new SortJacksonModule();
    }
    @Bean
    @ConditionalOnMissingBean(FeignClientConfigurer.class)
    public FeignClientConfigurer feignClientConfigurer() {
        return new FeignClientConfigurer() {};
    }
    private Encoder springEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) {
        AbstractFormWriter formWriter = formWriterProvider.getIfAvailable();
        if (formWriter != null) {
            return new SpringEncoder(new SpringPojoFormEncoder(formWriter), this.messageConverters);
        }
        return new SpringEncoder(new SpringFormEncoder(), this.messageConverters);
    }
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
    protected static class HystrixFeignConfiguration {
        @Bean
        @Scope("prototype")
        @ConditionalOnMissingBean
        @ConditionalOnProperty(name = "feign.hystrix.enabled")
        public Feign.Builder feignHystrixBuilder() {
            return HystrixFeign.builder();
        }

    }
    private class SpringPojoFormEncoder extends SpringFormEncoder {
        SpringPojoFormEncoder(AbstractFormWriter formWriter) {
            super();
            MultipartFormContentProcessor processor = (MultipartFormContentProcessor) getContentProcessor(MULTIPART);
            processor.addFirstWriter(formWriter);
        }
    }
}

02 开启Feign客户端

Spring Boot通过**@EnableFeignClients**注解开启Feign支持,目的是用于导入处理客户端配置,然后注入到IOC容器。

java 复制代码
@EnableFeignClients
@SpringBootApplication
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class);
    }
}
java 复制代码
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
    // 扫描包路径, 和basePackages属性一致
    String[] value() default {};
    
    // 扫描包路径
    String[] basePackages() default {};
    
    // 基础扫描基础类
    Class<?>[] basePackageClasses() default {};
    
    // 默认配置, 比如申明Decoder、Encoder和Contract
    Class<?>[] defaultConfiguration() default {};
    
    // 客户端配置注解
    Class<?>[] clients() default {};
}

2.1 客户端注册器

Feign使用注册器FeignClientsRegistrar注册默认客户端配置,客户端本地执行远程调用端口,然后注册到IOC容器进行管理。

2.1.1 注册默认配置

Feign通过FeignClientsRegistrar提供默认配置注册,默认为default.[配置类名]进行配置实现。

java 复制代码
class FeignClientsRegistrar 
    implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    private Environment environment;
    private ResourceLoader resourceLoader;
    
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata,
        BeanDefinitionRegistry registry) {
        registerDefaultConfiguration(metadata, registry);
        registerFeignClients(metadata, registry);
    }

    private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        // 获取@EnableFeignClients注解配置
        Map<String, Object> defaultAttrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
        // 获取属性配置
        if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
            String name;
            if (metadata.hasEnclosingClass()) {
                name = "default." + metadata.getEnclosingClassName();
            } else {
                name = "default." + metadata.getClassName();
            }
            registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration"));
        }
    }
    private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
        // 创建BeanDefinition
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
        // 添加构建参数值
        builder.addConstructorArgValue(name);
        builder.addConstructorArgValue(configuration);
        // 注册实例
        registry.registerBeanDefinition(
            name + "." + FeignClientSpecification.class.getSimpleName(),
            builder.getBeanDefinition()
        );
    }
}

2.1.2 FeignClient配置

Feign通过FeignClientsRegistrar扫描@FeignClient注解客户端配置,然后创建Feign客户端接口工厂实例Bean定义FeignClientFactoryBean注册到IOC容器。

java 复制代码
public @interface FeignClient {
    // 指定调用服务名称, 对应服务注册中心服务名称
    @AliasFor("name")
    String value() default "";

    // 与name意义一致
    @Deprecated
    String serviceId() default "";

    // 客户端上下文ID, 用于区分不同客户端
    String contextId() default "";

    // value别名
    @AliasFor("value")
    String name() default "";
    
    // 指定客户端限定符, 用于区分相同类型客户端
    String qualifier() default "";
    
    // 指定调用服务URL地址, 直接指定服务URL, 而不通过注册中心进行服务发现
    String url() default "";
    
    // 指定404作为正常响应处理, 默认为false
    boolean decode404() default false;
    
    // 指定客户端配置类, 用于配置客户端相关属性, 如超时时间、重试策略等
    Class<?>[] configuration() default {};
    
    // 指定客户端降级处理类, 远程调用失败降级逻辑
    Class<?> fallback() default void.class;
    
    // 指定客户端降级处理工厂类, 用于创建降级处理类实例
    Class<?> fallbackFactory() default void.class;

    // 指定客户端基础路径, 用于拼接请求URL
    String path() default "";

    // 指定客户端是否为主要的, 当存在多个客户端可以通过primary参数指定主要客户端
    boolean primary() default true;
}
java 复制代码
class FeignClientsRegistrar 
    implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    private Environment environment;
    private ResourceLoader resourceLoader;
    
	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata,
		BeanDefinitionRegistry registry) {
		registerDefaultConfiguration(metadata, registry);
		registerFeignClients(metadata, registry);
	}
    
	public void registerFeignClients(AnnotationMetadata metadata,
		BeanDefinitionRegistry registry) {
		LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();
        // 获取属性配置
		Map<String, Object> 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) {
            // 扫描器
			ClassPathScanningCandidateComponentProvider scanner = getScanner();
			scanner.setResourceLoader(this.resourceLoader);
			scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));
            // 扫描包
			Set<String> basePackages = getBasePackages(metadata);
			for (String basePackage : basePackages) {
                // 执行包扫描候选类
				candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
			}
		} else {
			for (Class<?> clazz : clients) {
				candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz));
			}
		}

		for (BeanDefinition candidateComponent : candidateComponents) {
			if (candidateComponent instanceof AnnotatedBeanDefinition) {
				// verify annotated class is an interface
				AnnotatedBeanDefinition bf = (AnnotatedBeanDefinition) candidateComponent;
				AnnotationMetadata amd = bf.getMetadata();
                
                // 必须是接口类
				Assert.isTrue(amd.isInterface(), "@FeignClient can only be specified on an interface");

                // 获取客户端配置@FeignClient
				Map<String, Object> attributes = amd
						.getAnnotationAttributes(FeignClient.class.getCanonicalName());

                // 获取客户端名称
				String name = getClientName(attributes);
                
                // 注册客户端配置
				registerClientConfiguration(registry, name, attributes.get("configuration"));

                // 注册客户端
				registerFeignClient(registry, amd, attributes);
			}
		}
	}

	private void registerFeignClient(BeanDefinitionRegistry registry,
		AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
		String className = annotationMetadata.getClassName();
        // 创建BeanDefinition
		BeanDefinitionBuilder definition = BeanDefinitionBuilder
				.genericBeanDefinition(FeignClientFactoryBean.class);
		validate(attributes);
		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();
		beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);

		// has a default, won't be null
		boolean primary = (Boolean) attributes.get("primary");

		beanDefinition.setPrimary(primary);

        // 别名
		String qualifier = getQualifier(attributes);
		if (StringUtils.hasText(qualifier)) {
			alias = qualifier;
		}

		BeanDefinitionHolder bdh = new BeanDefinitionHolder(beanDefinition, className,
				new String[] { alias });
		BeanDefinitionReaderUtils.registerBeanDefinition(bdh, registry);
	}
    
    protected Set<String> getBasePackages(AnnotationMetadata importingClassMetadata) {
        // 获取@EnableFeignClients注解
		Map<String, Object> attributes = importingClassMetadata
			.getAnnotationAttributes(EnableFeignClients.class.getCanonicalName());

		Set<String> basePackages = new HashSet<>();
		for (String pkg : (String[]) attributes.get("value")) {
			if (StringUtils.hasText(pkg)) {
				basePackages.add(pkg);
			}
		}
		for (String pkg : (String[]) attributes.get("basePackages")) {
			if (StringUtils.hasText(pkg)) {
				basePackages.add(pkg);
			}
		}
		for (Class<?> clazz : (Class[]) attributes.get("basePackageClasses")) {
			basePackages.add(ClassUtils.getPackageName(clazz));
		}
		if (basePackages.isEmpty()) {
			basePackages.add(ClassUtils.getPackageName(importingClassMetadata.getClassName()));
		}
		return basePackages;
	}
    // 扫描器
    protected ClassPathScanningCandidateComponentProvider getScanner() {
		return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
			@Override
			protected boolean isCandidateComponent(AnnotatedBeanDefinition abd) {
				if (abd.getMetadata().isIndependent()) {
					if (!abd.getMetadata().isAnnotation()) {
						return true;
					}
				}
				return false;
			}
		};
	}
}

2.2 客户端工厂

Feign创建FeignClientFactoryBean类型BeanDefinition提供客户端实现支持,底层通过代理实现接口方法调用逻辑。

java 复制代码
class FeignClientFactoryBean
	implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
    private Class<?> type;
	private String name;
	private String url;
	private String contextId;
	private String path;
	private boolean decode404;
    // 是否使用父容器上下文
	private boolean inheritParentContext = true;
	private ApplicationContext applicationContext;
	private Class<?> fallback = void.class;
	private Class<?> fallbackFactory = void.class;
	private int readTimeoutMillis = new Request.Options().readTimeoutMillis();
	private int connectTimeoutMillis = new Request.Options().connectTimeoutMillis();

    @Override
	public Object getObject() throws Exception {
		return getTarget();
	}
    
    <T> T getTarget() {
        // 获取FeignContext上下文
		FeignContext context = applicationContext.getBean(FeignContext.class);
		Feign.Builder builder = feign(context);
		if (!StringUtils.hasText(url)) {
			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 LoadBalancerFeignClient) {
				client = ((LoadBalancerFeignClient) client).getDelegate();
			}
			if (client instanceof FeignBlockingLoadBalancerClient) {
				client = ((FeignBlockingLoadBalancerClient) client).getDelegate();
			}
			builder.client(client);
		}
		Targeter tgt = get(context, Targeter.class);
		return (T) tgt.target(this, builder, context, new HardCodedTarget<>(type, name, url));
	}
    protected <T> T get(FeignContext context, Class<T> type) {
		T instance = context.getInstance(contextId, type);
		if (instance == null) {
			throw new IllegalStateException(...);
		}
		return instance;
	}
    protected <T> T getOptional(FeignContext context, Class<T> type) {
		return context.getInstance(contextId, type);
	}
	protected <T> T getInheritedAwareOptional(FeignContext context, Class<T> type) {
		if (inheritParentContext) {
			return getOptional(context, type);
		}
		return context.getInstanceWithoutAncestors(contextId, type);
	}
}
java 复制代码
class FeignClientFactoryBean
	implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
    protected Feign.Builder feign(FeignContext context) {
        // 获取日志LoggerFactory
		FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
		Logger logger = loggerFactory.create(type);

		// @formatter:off
		Feign.Builder builder = get(context, Feign.Builder.class)
				// required values
				.logger(logger)
				.encoder(get(context, Encoder.class))    // 编码器
				.decoder(get(context, Decoder.class))    // 解码器
				.contract(get(context, Contract.class)); // 锲约
		// @formatter:on
        // 配置客户端
		configureFeign(context, builder);

		return builder;
	}
    
    protected void configureFeign(FeignContext context, Feign.Builder builder) {
        // 获取配置
		FeignClientProperties properties = applicationContext.getBean(FeignClientProperties.class);
		FeignClientConfigurer feignClientConfigurer = getOptional(context, FeignClientConfigurer.class);
		setInheritParentContext(feignClientConfigurer.inheritParentConfiguration());

		if (properties != null && inheritParentContext) {
            Map<String, FeignClientConfiguration> config = properties.getConfig();
			if (properties.isDefaultToProperties()) {
				configureUsingConfiguration(context, builder);
				configureUsingProperties(config.get(properties.getDefaultConfig()), builder);
				configureUsingPropertiesconfig.get(contextId), builder);
			} else {
				configureUsingProperties(config.get(properties.getDefaultConfig()), builder);
				configureUsingProperties(config.get(contextId), builder);
				configureUsingConfiguration(context, builder);
			}
		} else {
			configureUsingConfiguration(context, builder);
		}
	}
    protected void configureUsingConfiguration(FeignContext context, Feign.Builder builder) {
		Logger.Level level = getInheritedAwareOptional(context, Logger.Level.class);
		if (level != null) {
			builder.logLevel(level);
		}
		Retryer retryer = getInheritedAwareOptional(context, Retryer.class);
		if (retryer != null) {
			builder.retryer(retryer);
		}
		ErrorDecoder errorDecoder = getInheritedAwareOptional(context, ErrorDecoder.class);
		if (errorDecoder != null) {
			builder.errorDecoder(errorDecoder);
		}
		else {
			FeignErrorDecoderFactory errorDecoderFactory = getOptional(context, FeignErrorDecoderFactory.class);
			if (errorDecoderFactory != null) {
				ErrorDecoder factoryErrorDecoder = errorDecoderFactory.create(type);
				builder.errorDecoder(factoryErrorDecoder);
			}
		}
		Request.Options options = getInheritedAwareOptional(context, Request.Options.class);
		if (options != null) {
			builder.options(options);
			readTimeoutMillis = options.readTimeoutMillis();
			connectTimeoutMillis = options.connectTimeoutMillis();
		}
        // 获取请求拦截器
		Map<String, RequestInterceptor> requestInterceptors = getInheritedAwareInstances(
				context, RequestInterceptor.class);
		if (requestInterceptors != null) {
            // 拦截器
			List<RequestInterceptor> interceptors = new ArrayList<>(requestInterceptors.values());
			AnnotationAwareOrderComparator.sort(interceptors);
			builder.requestInterceptors(interceptors);
		}
		QueryMapEncoder queryMapEncoder = getInheritedAwareOptional(context, QueryMapEncoder.class);
		if (queryMapEncoder != null) {
			builder.queryMapEncoder(queryMapEncoder);
		}
		if (decode404) {
			builder.decode404();
		}
        // 异常传播策略
		ExceptionPropagationPolicy exceptionPropagationPolicy = getInheritedAwareOptional(
				context, ExceptionPropagationPolicy.class);
		if (exceptionPropagationPolicy != null) {
			builder.exceptionPropagationPolicy(exceptionPropagationPolicy);
		}
	}
}

2.3 客户端实例

Feign默认使用DefaultTargeter创建本地方法远程调用客户端,底层创建方法接口JDK代理,仅需通过接口注解信息就可以发起远程方法调用。

java 复制代码
class DefaultTargeter implements Targeter {
	@Override
	public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget<T> target) {
		return feign.target(target);
	}
}
java 复制代码
public abstract class Feign {
    public <T> T target(Target<T> target) {
        return build().newInstance(target);
    }
    public static class Builder {
        // ...
        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);
            
            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);
            
            // 创建反射客户端
            return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
        }
    }
}
java 复制代码
public class ReflectiveFeign extends Feign {
    // ...
    @Override
    public <T> T newInstance(Target<T> target) {
        // <客户端, 处理器> 
        Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
        Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<>();
        List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<>();

        for (Method method : target.type().getMethods()) {
            if (method.getDeclaringClass() == Object.class) {
                continue;
            }
            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);
        T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
                new Class<?>[] {target.type()}, handler);
        // 绑定处理器
        for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
            defaultMethodHandler.bindTo(proxy);
        }
        return proxy;
    }
}
java 复制代码
static final class ParseHandlersByName {
    // ...
    public Map<String, MethodHandler> apply(Target target) {
        // 获取锲约元数据
        List<MethodMetadata> metadata = contract.parseAndValidateMetadata(target.type());
        Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
        for (MethodMetadata md : metadata) {
            ReflectiveFeign.BuildTemplateByResolvingArgs buildTemplate;
            if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
                buildTemplate = new ReflectiveFeign.BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
            } else if (md.bodyIndex() != null) {
                buildTemplate = new ReflectiveFeign.BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
            } else {
                buildTemplate = new ReflectiveFeign.BuildTemplateByResolvingArgs(md, queryMapEncoder, target);
            }
            if (md.isIgnored()) {
                result.put(md.configKey(), args -> {
                    throw new IllegalStateException(md.configKey() + " is not a method handled by feign");
                });
            } else {
                result.put(md.configKey(), factory.create(target, md, buildTemplate, options, decoder, errorDecoder));
            }
        }
        return result;
    }
}

static class Factory {
    // ...
    public MethodHandler create(Target<?> target,
        MethodMetadata md, RequestTemplate.Factory buildTemplateFromArgs,
        Options options, Decoder decoder, ErrorDecoder errorDecoder) {
        return new SynchronousMethodHandler(target, client, retryer, requestInterceptors, logger,
                logLevel, md, buildTemplateFromArgs, options, decoder,
                errorDecoder, decode404, closeAfterDecode, propagationPolicy, forceDecoding);
    }
}
java 复制代码
public interface InvocationHandlerFactory {
    InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch);
    
    interface MethodHandler {
        Object invoke(Object[] argv) throws Throwable;
    }

    static final class Default implements InvocationHandlerFactory {
        @Override
        public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
            return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
        }
    }
}
java 复制代码
static class FeignInvocationHandler implements InvocationHandler {
    private final Target target;
    private final Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;

    FeignInvocationHandler(Target target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch) {
        this.target = checkNotNull(target, "target");
        this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
    }

    @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);
    }
}
相关推荐
小安运维日记37 分钟前
CKS认证 | Day4 最小化微服务漏洞
安全·docker·微服务·云原生·容器·kubernetes
Code季风3 小时前
将 gRPC 服务注册到 Consul:从配置到服务发现的完整实践(上)
数据库·微服务·go·json·服务发现·consul
Code季风7 小时前
微服务分布式配置中心:Gin Web 服务层与 gRPC 服务层集成 Nacos 实战
分布式·微服务·rpc·架构·go·gin·consul
Right.W7 小时前
生成PDF文件(基于 iText PDF )
spring cloud·pdf
步、步、为营9 小时前
.net微服务框架dapr保存和获取状态
微服务·架构·.net
guojl12 小时前
微服务OpenFeign使用手册
spring cloud·微服务
chanalbert12 小时前
从单体到微服务:Spring Cloud 开篇与微服务设计
spring boot·spring·spring cloud
Code季风1 天前
Gin Web 层集成 Viper 配置文件和 Zap 日志文件指南(下)
前端·微服务·架构·go·gin