// 官网地址: https://docs.spring.io/spring-cloud-openfeign/reference/spring-cloud-openfeign.html
// 开启Feign客户端调用
// @TODO 原理,Feign接口的实现原理,返回值如何处理,如何拦截
@EnableFeignClients
public class App {
}
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
}
// 该配置类会导入所有的@FeignClient类和@FeignClient中configuration属性对应的配置类,以及@EnableFeignClients中defaultConfiguration的配置类
public class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
// 资源加载器
private ResourceLoader resourceLoader;
// 环境对象
private Environment environment;
FeignClientsRegistrar() {
}
// 校验FeignClient的fallback实现,不能是接口
static void validateFallback(final Class clazz) {
Assert.isTrue(!clazz.isInterface(), "Fallback class must implement the interface annotated by @FeignClient");
}
// 校验FeignClient的fallbackFactory实现,不能是接口
static void validateFallbackFactory(final Class clazz) {
Assert.isTrue(!clazz.isInterface(), "Fallback factory must produce instances " + "of fallback classes that implement the interface annotated by @FeignClient");
}
// 获取服务名称,验证一下主机名,主要是校验一下是否填写了服务名称
// 获取服务名称,优先级: serviceId > name > value
public static String getName(String name) {
if (!StringUtils.hasText(name)) {
return "";
}
String host = null;
String url;
// 如果服务名称不是以http开头,则添加http前缀
if (!name.startsWith("http://") && !name.startsWith("https://")) {
url = "http://" + name;
} else {
url = name;
}
// 获取主机名,http://后面的就是主机名,主要是校验一下是否填写了服务名称
host = new URI(url).getHost();
// 确定主机名不为空
Assert.state(host != null, "Service id not legal hostname (" + name + ")");
return name;
}
// 获取URL,将url的值拼接上http://
static String getUrl(String url) {
if (StringUtils.hasText(url) && !(url.startsWith("#{") && url.contains("}"))) {
if (!url.contains("://")) {
url = "http://" + url;
}
new URL(url);
}
return url;
}
// 获取路径
static String getPath(String path) {
// 添加缺失的前缀"/"以及删除多余的"/"后缀
if (StringUtils.hasText(path)) {
path = path.trim();
if (!path.startsWith("/")) {
path = "/" + path;
}
if (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
}
return path;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// 注册EnableFeignClients中指定的defaultConfiguration属性值对应的配置类
this.registerDefaultConfiguration(metadata, registry);
// 注册标注了@FeignClient类
this.registerFeignClients(metadata, registry);
}
// 注册EnableFeignClients中指定的defaultConfiguration属性值对应的配置类
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();
}
// 注册默认的配置类
this.registerClientConfiguration(registry, name, "default", defaultAttrs.get("defaultConfiguration"));
}
}
// 注册所有FeignClient类
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();
// 获取该注解的所有属性
Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
// 指定标注了@FeignClient的类,如果指定了,就不会扫描
final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");
if (clients == null || clients.length == 0) {
// 创建包扫描器
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
// 添加扫描条件,扫描包含@FeignClient注解的类
scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));
// 获取需要扫描的包路径
Set<String> basePackages = getBasePackages(metadata);
// 开始扫描所有包
for (String basePackage : basePackages) {
candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
}
} else {
// 如果指定了要扫描的@FeignClient,那么直接将FeignClient类包装成BeanDefinition
for (Class<?> clazz : clients) {
candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz));
}
}
// 遍历所有符合条件的类
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition beanDefinition) {
// 扫描的类必须是接口
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface");
// 获取FeignClient该类的属性
Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
// 获取客户端名称,优先级 contextId > value > name > serviceId
String name = this.getClientName(attributes);
// 获取接口名
String className = annotationMetadata.getClassName();
// 获取该用于该FeignClient的自定义配置类configuration属性值
this.registerClientConfiguration(registry, name, className, attributes.get("configuration"));
// 注册FeignClient接口
this.registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
// 注册FeignClient类
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
// 获取接口名
String className = annotationMetadata.getClassName();
// 如果spring.cloud.openfeign.lazy-attributes-resolution配置为false(默认为false)
if (String.valueOf(false).equals(environment.getProperty("spring.cloud.openfeign.lazy-attributes-resolution", String.valueOf(false)))) {
// 注册该Bean
this.eagerlyRegisterFeignClientBeanDefinition(className, attributes, registry);
} else {
// 注册延迟的FeignClient,逻辑和注册逻辑和eagerlyRegisterFeignClientBeanDefinition一样
// 唯一的区别在于该Bean是懒加载的,并且给定创建好的实例对象,而不是执行Spring默认实例化的逻辑
this.lazilyRegisterFeignClientBeanDefinition(className, attributes, registry);
}
}
// 立刻注册FeignClient
private void eagerlyRegisterFeignClientBeanDefinition(String className, Map<String, Object> attributes, BeanDefinitionRegistry registry) {
// 验证FeignClient注解的配置
this.validate(attributes);
// 注册生成FeignClient的FactoryBean
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
// 将FeignClient的属性设置到FeignClientFactoryBean中
definition.addPropertyValue("url", getUrl(null, attributes));
// 基础路径
definition.addPropertyValue("path", getPath(null, attributes));
// 获取服务名称
String name = this.getName(attributes);
definition.addPropertyValue("name", name);
// 获取contextId,如果没有单独设置contextI属性,默认为getName()服务名称
String contextId = getContextId(null, attributes);
definition.addPropertyValue("contextId", contextId);
definition.addPropertyValue("type", className);
// 是否应该解码404而不是抛出feigexception,默认为false
// 如果为true,404也会返回对应的结果
definition.addPropertyValue("dismiss404", Boolean.parseBoolean(String.valueOf(attributes.get("dismiss404"))));
// 获取兜底的处理类
Object fallback = attributes.get("fallback");
if (fallback != null) {
definition.addPropertyValue("fallback", (fallback instanceof Class ? fallback : ClassUtils.resolveClassName(fallback.toString(), null)));
}
Object fallbackFactory = attributes.get("fallbackFactory");
if (fallbackFactory != null) {
definition.addPropertyValue("fallbackFactory", fallbackFactory instanceof Class ? fallbackFactory : ClassUtils.resolveClassName(fallbackFactory.toString(), null));
}
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
// 设置注入模式,为ByType
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
definition.addPropertyValue("refreshableClient", isClientRefreshEnabled());
// 获取注解的qualifiers属性,该属性是指定@FeignClient的限定名,也就是FeignClient的bean的别名
String[] qualifiers = this.getQualifiers(attributes);
if (ObjectUtils.isEmpty(qualifiers)) {
// 如果没有设置,默认给定为contextId+FeignClient
qualifiers = new String[]{contextId + "FeignClient"};
}
definition.addPropertyValue("qualifiers", qualifiers);
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
// 设置Primary属性
boolean primary = (Boolean) attributes.get("primary");
beanDefinition.setPrimary(primary);
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
// 注册FeignClient类
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
// 注册可刷新的Bean,就是该Bean的作用域为refresh,在配置刷新的时候会进行重新创建
// 注册Request.Options,使用OptionsFactoryBean创建
this.registerRefreshableBeanDefinition(registry, contextId, Request.Options.class, OptionsFactoryBean.class);
// 注册可刷新的Bean,就是该Bean的作用域为refresh,在配置刷新的时候会进行重新创建
// 注册RefreshableUrl,使用RefreshableUrlFactoryBean
this.registerRefreshableBeanDefinition(registry, contextId, RefreshableUrl.class, RefreshableUrlFactoryBean.class);
}
/**
* <pre>
* 懒加载注册FeignClient
* 逻辑和注册逻辑和eagerlyRegisterFeignClientBeanDefinition一样
* 唯一的区别在于该Bean是懒加载的,并且给定创建好的实例对象,而不是执行Spring默认实例化的逻辑
* {@link FeignClientsRegistrar#eagerlyRegisterFeignClientBeanDefinition}
* </pre>
*/
private void lazilyRegisterFeignClientBeanDefinition(String className, Map<String, Object> attributes, BeanDefinitionRegistry registry) {
ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory ? (ConfigurableBeanFactory) registry : null;
Class clazz = ClassUtils.resolveClassName(className, null);
String contextId = this.getContextId(beanFactory, attributes);
String name = this.getName(attributes);
FeignClientFactoryBean factoryBean = new FeignClientFactoryBean();
factoryBean.setBeanFactory(beanFactory);
factoryBean.setName(name);
factoryBean.setContextId(contextId);
factoryBean.setType(clazz);
factoryBean.setRefreshableClient(isClientRefreshEnabled());
// 给定Bean的实例对象
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> {
factoryBean.setUrl(this.getUrl(beanFactory, attributes));
factoryBean.setPath(this.getPath(beanFactory, attributes));
factoryBean.setDismiss404(Boolean.parseBoolean(String.valueOf(attributes.get("dismiss404"))));
Object fallback = attributes.get("fallback");
if (fallback != null) {
factoryBean.setFallback(fallback instanceof Class ? (Class<?>) fallback : ClassUtils.resolveClassName(fallback.toString(), null));
}
Object fallbackFactory = attributes.get("fallbackFactory");
if (fallbackFactory != null) {
factoryBean.setFallbackFactory(fallbackFactory instanceof Class ? (Class<?>) fallbackFactory : ClassUtils.resolveClassName(fallbackFactory.toString(), null));
}
return factoryBean.getObject();
});
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
// 设置为懒加载
definition.setLazyInit(true);
this.validate(attributes);
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
beanDefinition.setAttribute("feignClientsRegistrarFactoryBean", factoryBean);
boolean primary = (Boolean) attributes.get("primary");
beanDefinition.setPrimary(primary);
String[] qualifiers = getQualifiers(attributes);
if (ObjectUtils.isEmpty(qualifiers)) {
qualifiers = new String[]{contextId + "FeignClient"};
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
this.registerRefreshableBeanDefinition(registry, contextId, Request.Options.class, OptionsFactoryBean.class);
this.registerRefreshableBeanDefinition(registry, contextId, RefreshableUrl.class, RefreshableUrlFactoryBean.class);
}
// 验证FeignClient注解的配置
private void validate(Map<String, Object> attributes) {
// 获取FeignClient的所有属性
AnnotationAttributes annotation = AnnotationAttributes.fromMap(attributes);
// 验证fallback
// 校验FeignClient的fallback实现,不能是接口
validateFallback(annotation.getClass("fallback"));
// 验证fallbackFacotory
// 校验FeignClient的fallbackFactory实现,不能是接口
validateFallbackFactory(annotation.getClass("fallbackFactory"));
}
// 获取服务名称,优先级: serviceId > name > value
public String getName(Map<String, Object> attributes) {
return this.getName(null, attributes);
}
// 获取服务名称,解析服务名称的占位符,优先级: serviceId > name > value
public String getName(ConfigurableBeanFactory beanFactory, Map<String, Object> attributes) {
String name = (String) attributes.get("serviceId");
if (!StringUtils.hasText(name)) {
name = (String) attributes.get("name");
}
if (!StringUtils.hasText(name)) {
name = (String) attributes.get("value");
}
// 解析服务名称,就是解析服务名称中的占位符
name = this.resolve(beanFactory, name);
return this.getName(name);
}
// 获取上下文ID,如果为空,则获取服务名
private String getContextId(ConfigurableBeanFactory beanFactory, Map<String, Object> attributes) {
String contextId = (String) attributes.get("contextId");
if (!StringUtils.hasText(contextId)) {
return this.getName(attributes);
}
contextId = this.resolve(beanFactory, contextId);
return this.getName(contextId);
}
// 解析属性值的中的占位符
private String resolve(ConfigurableBeanFactory beanFactory, String value) {
if (StringUtils.hasText(value)) {
if (beanFactory == null) {
return this.environment.resolvePlaceholders(value);
}
BeanExpressionResolver resolver = beanFactory.getBeanExpressionResolver();
String resolved = beanFactory.resolveEmbeddedValue(value);
if (resolver == null) {
return resolved;
}
Object evaluateValue = resolver.evaluate(resolved, new BeanExpressionContext(beanFactory, null));
if (evaluateValue != null) {
return String.valueOf(evaluateValue);
}
return null;
}
return value;
}
// 解析url,如果设置了url属性,则发送的url则为指定的,如果为指定url,则创建对象的时候会处理url,为http前缀+服务名(根据设定的contextId,name,value)属性来决定
private String getUrl(ConfigurableBeanFactory beanFactory, Map<String, Object> attributes) {
String url = resolve(beanFactory, (String) attributes.get("url"));
return getUrl(url);
}
// 解析接口的基础路径
private String getPath(ConfigurableBeanFactory beanFactory, Map<String, Object> attributes) {
String path = resolve(beanFactory, (String) attributes.get("path"));
return getPath(path);
}
// 获取类扫描器,该扫描器负责扫描独立的(非内部类)非注解类
protected ClassPathScanningCandidateComponentProvider getScanner() {
return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
boolean isCandidate = false;
// 如果独立的类(不是内部类)
if (beanDefinition.getMetadata().isIndependent()) {
// 并且该类不是注解,则满足条件
if (!beanDefinition.getMetadata().isAnnotation()) {
isCandidate = true;
}
}
return isCandidate;
}
};
}
// 获取需要扫描的包路径
protected Set<String> getBasePackages(AnnotationMetadata importingClassMetadata) {
// 获取@EnableFeignClients的所有属性
Map<String, Object> attributes = importingClassMetadata.getAnnotationAttributes(EnableFeignClients.class.getCanonicalName());
Set<String> basePackages = new HashSet<>();
// 获取value值
for (String pkg : (String[]) attributes.get("value")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
// 获取basePackages值
for (String pkg : (String[]) attributes.get("basePackages")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
// 获取basePackageClasses值
for (Class<?> clazz : (Class[]) attributes.get("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
// 将他们统一保存起来,如果是类名则保存类的包名,如果都没有设置,那么获取标注@EnableFeignClients该注解的类的包名
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(importingClassMetadata.getClassName()));
}
return basePackages;
}
// 解析注解的中该FeignClient的qualifier的Bean别名
private String getQualifier(Map<String, Object> client) {
if (client == null) {
return null;
}
String qualifier = (String) client.get("qualifier");
if (StringUtils.hasText(qualifier)) {
return qualifier;
}
return null;
}
// 获取客户端名称,优先级 contextId > value > name > serviceId
private String getClientName(Map<String, Object> client) {
if (client == null) {
return null;
}
// 先获取是否存在contextId
String value = (String) client.get("contextId");
// 如果不存在,再获取value值
if (!StringUtils.hasText(value)) {
value = (String) client.get("value");
}
// 不存在value,则获取name
if (!StringUtils.hasText(value)) {
value = (String) client.get("name");
}
// 不存在name,则获取serviceId
if (!StringUtils.hasText(value)) {
value = (String) client.get("serviceId");
}
// 返回获取的服务名
if (StringUtils.hasText(value)) {
return value;
}
// 如果不存在任何服务名称,抛出异常
throw new IllegalStateException("Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName());
}
/**
* 注册用于指定FeignClient的自定义配置类,类型为{@link FeignClientSpecification}
*
* @param name 配置类名称
* @param className 配置类类名
* @param configuration
*/
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object className, Object configuration) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(className);
builder.addConstructorArgValue(configuration);
registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(), builder.getBeanDefinition());
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
/**
* 注册refresh作用域的Bean
*
* @param contextId feign客户端的唯一标识
* @param beanType 注册的Bean的类型
* @param factoryBeanType 生成Bean的FactoryBean类型
*/
private void registerRefreshableBeanDefinition(BeanDefinitionRegistry registry, String contextId, Class<?> beanType, Class<?> factoryBeanType) {
// 是否启用客户端刷新功能spring.cloud.openfeign.client.refresh-enabled
// 就是注册refresh作用域的Bean对象
if (this.isClientRefreshEnabled()) {
String beanName = beanType.getCanonicalName() + "-" + contextId;
// 注册该Bean,BeanClass为factoryBeanType
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(factoryBeanType);
// 作用域为refresh
definitionBuilder.setScope("refresh");
// 设置上下文ID
definitionBuilder.addPropertyValue("contextId", contextId);
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(definitionBuilder.getBeanDefinition(), beanName);
// 创建作用域代理
definitionHolder = ScopedProxyUtils.createScopedProxy(definitionHolder, registry, true);
// 注册该Bean
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}
}
// 是否启用客户端刷新功能spring.cloud.openfeign.client.refresh-enabled
// 就是注册refresh作用域的Bean对象
private boolean isClientRefreshEnabled() {
return environment.getProperty("spring.cloud.openfeign.client.refresh-enabled", Boolean.class, false);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({FeignClientProperties.class, FeignHttpClientProperties.class, FeignEncoderProperties.class})
public class FeignAutoConfiguration {
private static final Log LOG = LogFactory.getLog(FeignAutoConfiguration.class);
// 用于描述FeignClient的自定义配置类对象信息,以下两种会封装成FeignClientSpecification的Bean对象
// 情况一: FeignClient的客户端名称(可能是@FeignClient的contextId,value,name,serviceId属性)
// 情况二: @EnableFeignClients注解设置了"defaultConfiguration"默认的配置为了属性,则名称为"default."+标注该注解的类名
@Autowired(required = false)
private List<FeignClientSpecification> configurations = new ArrayList<>();
@Bean
public HasFeatures feignFeature() {
return HasFeatures.namedFeature("Feign", Feign.class);
}
// FeignClient的工厂类,它负责管理所有的Feign的客户端的ApplicationContext对象,以及FeignClient独有的Bean对象
@Bean
public FeignClientFactory feignContext() {
FeignClientFactory context = new FeignClientFactory();
context.setConfigurations(this.configurations);
return context;
}
// AOT 指的是 “Ahead-of-Time” 编译,它是一种将 Java 代码提前编译成本地机器代码的技术,以在运行时提高性能和减少启动时间
@Bean
static FeignChildContextInitializer feignChildContextInitializer(GenericApplicationContext parentContext, FeignClientFactory feignClientFactory) {
return new FeignChildContextInitializer(parentContext, feignClientFactory);
}
@Bean
static FeignClientBeanFactoryInitializationAotProcessor feignClientBeanFactoryInitializationCodeGenerator(GenericApplicationContext applicationContext, FeignClientFactory feignClientFactory) {
return new FeignClientBeanFactoryInitializationAotProcessor(applicationContext, feignClientFactory);
}
// 如果开启了Feign的缓存,添加一个对InvocationHandlerFactory的增强器,默认为true
@Bean
@ConditionalOnProperty(value = "spring.cloud.openfeign.cache.enabled", matchIfMissing = true)
@ConditionalOnBean(CacheInterceptor.class)
public Capability cachingCapability(CacheInterceptor cacheInterceptor) {
return new CachingCapability(cacheInterceptor);
}
// 如果开启了json,默认为true
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({Module.class, Page.class, Sort.class})
@ConditionalOnProperty(value = "spring.cloud.openfeign.autoconfiguration.jackson.enabled", havingValue = "true", matchIfMissing = true)
protected static class FeignJacksonConfiguration {
@Bean
@ConditionalOnMissingBean(PageJacksonModule.class)
public PageJacksonModule pageJacksonModule() {
return new PageJacksonModule();
}
@Bean
@ConditionalOnMissingBean(SortJacksonModule.class)
public SortJacksonModule sortModule() {
return new SortJacksonModule();
}
}
@Configuration(proxyBeanMethods = false)
// 如果Feign禁用熔断机制,则注册默认创建FeignClient代理对象的DefaultTargeter的Bean
@Conditional(FeignCircuitBreakerDisabledConditions.class)
protected static class DefaultFeignTargeterConfiguration {
@Bean
@ConditionalOnMissingBean
public Targeter feignTargeter() {
return new DefaultTargeter();
}
}
// Feign的熔断配置
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(CircuitBreaker.class)
// 如果Feign启用熔断,则注册默认创建FeignClient代理对象的DefaultTargeter的Bean
@ConditionalOnProperty(value = "spring.cloud.openfeign.circuitbreaker.enabled", havingValue = "true")
protected static class CircuitBreakerPresentFeignTargeterConfiguration {
// 当不存在断路器工厂CircuitBreakerFactory,则不需要使用支持断路的FeignClient代理对象,直接返回DefaultTargeter
@Bean
@ConditionalOnMissingBean(CircuitBreakerFactory.class)
public Targeter defaultFeignTargeter() {
return new DefaultTargeter();
}
@Bean
@ConditionalOnMissingBean(CircuitBreakerNameResolver.class)
@ConditionalOnProperty(value = "spring.cloud.openfeign.circuitbreaker.alphanumeric-ids.enabled", havingValue = "false")
public CircuitBreakerNameResolver circuitBreakerNameResolver() {
return new DefaultCircuitBreakerNameResolver();
}
@Bean
@ConditionalOnMissingBean(CircuitBreakerNameResolver.class)
@ConditionalOnProperty(value = "spring.cloud.openfeign.circuitbreaker.alphanumeric-ids.enabled", havingValue = "true", matchIfMissing = true)
public CircuitBreakerNameResolver alphanumericCircuitBreakerNameResolver() {
return new AlphanumericCircuitBreakerNameResolver();
}
// 当存在断路器工厂CircuitBreakerFactory,则需要使用支持断路的FeignClient代理对象,创建FeignCircuitBreakerTargeter
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(CircuitBreakerFactory.class)
public Targeter circuitBreakerFeignTargeter(CircuitBreakerFactory circuitBreakerFactory, @Value("${spring.cloud.openfeign.circuitbreaker.group.enabled:false}") boolean circuitBreakerGroupEnabled, CircuitBreakerNameResolver circuitBreakerNameResolver) {
return new FeignCircuitBreakerTargeter(circuitBreakerFactory, circuitBreakerGroupEnabled, circuitBreakerNameResolver);
}
static class DefaultCircuitBreakerNameResolver implements CircuitBreakerNameResolver {
@Override
public String resolveCircuitBreakerName(String feignClientName, Target<?> target, Method method) {
return Feign.configKey(target.type(), method);
}
}
static class AlphanumericCircuitBreakerNameResolver extends DefaultCircuitBreakerNameResolver {
@Override
public String resolveCircuitBreakerName(String feignClientName, Target<?> target, Method method) {
return super.resolveCircuitBreakerName(feignClientName, target, method).replaceAll("[^a-zA-Z0-9]", "");
}
}
}
// 开启OKHttp配置,用于发送请求
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnMissingBean(okhttp3.OkHttpClient.class)
@ConditionalOnProperty("spring.cloud.openfeign.okhttp.enabled")
protected static class OkHttpFeignConfiguration {
private okhttp3.OkHttpClient okHttpClient;
@Bean
@ConditionalOnMissingBean
public okhttp3.OkHttpClient.Builder okHttpClientBuilder() {
return new okhttp3.OkHttpClient.Builder();
}
@Bean
@ConditionalOnMissingBean(ConnectionPool.class)
public ConnectionPool httpClientConnectionPool(FeignHttpClientProperties httpClientProperties) {
int maxTotalConnections = httpClientProperties.getMaxConnections();
long timeToLive = httpClientProperties.getTimeToLive();
TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
return new ConnectionPool(maxTotalConnections, timeToLive, ttlUnit);
}
@Bean
public okhttp3.OkHttpClient okHttpClient(okhttp3.OkHttpClient.Builder builder, ConnectionPool connectionPool, FeignHttpClientProperties httpClientProperties) {
boolean followRedirects = httpClientProperties.isFollowRedirects();
int connectTimeout = httpClientProperties.getConnectionTimeout();
boolean disableSslValidation = httpClientProperties.isDisableSslValidation();
Duration readTimeout = httpClientProperties.getOkHttp().getReadTimeout();
List<Protocol> protocols = httpClientProperties.getOkHttp().getProtocols().stream().map(Protocol::valueOf).collect(Collectors.toList());
if (disableSslValidation) {
disableSsl(builder);
}
this.okHttpClient = builder.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
.followRedirects(followRedirects).readTimeout(readTimeout).connectionPool(connectionPool)
.protocols(protocols).build();
return this.okHttpClient;
}
private void disableSsl(okhttp3.OkHttpClient.Builder builder) {
try {
X509TrustManager disabledTrustManager = new DisableValidationTrustManager();
TrustManager[] trustManagers = new TrustManager[1];
trustManagers[0] = disabledTrustManager;
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, new java.security.SecureRandom());
SSLSocketFactory disabledSSLSocketFactory = sslContext.getSocketFactory();
builder.sslSocketFactory(disabledSSLSocketFactory, disabledTrustManager);
builder.hostnameVerifier(new TrustAllHostnames());
} catch (NoSuchAlgorithmException | KeyManagementException e) {
LOG.warn("Error setting SSLSocketFactory in OKHttpClient", e);
}
}
@PreDestroy
public void destroy() {
if (this.okHttpClient != null) {
this.okHttpClient.dispatcher().executorService().shutdown();
this.okHttpClient.connectionPool().evictAll();
}
}
@Bean
@ConditionalOnMissingBean(Client.class)
public Client feignClient(okhttp3.OkHttpClient client) {
return new OkHttpClient(client);
}
class DisableValidationTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
class TrustAllHostnames implements HostnameVerifier {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
}
}
// 开启httpclient配置,用于发送请求
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ApacheHttp5Client.class)
@ConditionalOnMissingBean(org.apache.hc.client5.http.impl.classic.CloseableHttpClient.class)
@ConditionalOnProperty(value = "spring.cloud.openfeign.httpclient.hc5.enabled", havingValue = "true", matchIfMissing = true)
@Import(org.springframework.cloud.openfeign.clientconfig.HttpClient5FeignConfiguration.class)
protected static class HttpClient5FeignConfiguration {
@Bean
@ConditionalOnMissingBean(Client.class)
public Client feignClient(org.apache.hc.client5.http.impl.classic.CloseableHttpClient httpClient5) {
return new ApacheHttp5Client(httpClient5);
}
}
// 开启oauth2
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(OAuth2AuthorizedClientManager.class)
@ConditionalOnProperty("spring.cloud.openfeign.oauth2.enabled")
protected static class Oauth2FeignConfiguration {
@Bean
@ConditionalOnBean({OAuth2AuthorizedClientService.class, ClientRegistrationRepository.class})
@ConditionalOnMissingBean
OAuth2AuthorizedClientManager feignOAuth2AuthorizedClientManager(ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientService oAuth2AuthorizedClientService) {
return new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, oAuth2AuthorizedClientService);
}
@Bean
@ConditionalOnBean(OAuth2AuthorizedClientManager.class)
public OAuth2AccessTokenInterceptor defaultOAuth2AccessTokenInterceptor(@Value("${spring.cloud.openfeign.oauth2.clientRegistrationId:}") String clientRegistrationId, OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager) {
return new OAuth2AccessTokenInterceptor(clientRegistrationId, oAuth2AuthorizedClientManager);
}
}
}
// 同时满足下面两个条件,则禁用熔断
public class FeignCircuitBreakerDisabledConditions extends AnyNestedCondition {
FeignCircuitBreakerDisabledConditions() {
super(ConfigurationPhase.PARSE_CONFIGURATION);
}
// 不存在CircuitBreaker类
@ConditionalOnMissingClass("org.springframework.cloud.client.circuitbreaker.CircuitBreaker")
static class CircuitBreakerClassMissing {
}
// 未开启熔断才会满足该条件,默认值为true,也就是说必须明明确禁用才会禁用
@ConditionalOnProperty(value = "spring.cloud.openfeign.circuitbreaker.enabled", havingValue = "false", matchIfMissing = true)
static class CircuitBreakerDisabled {
}
}
@ConfigurationProperties("spring.cloud.openfeign.client")
public class FeignClientProperties {
// 默认配置优先
private boolean defaultToProperties = true;
// 默认的全局配置配置,所有Feign客户端生效
private String defaultConfig = "default";
// contextId -> 该contextId对应的Feign客户端配置
private Map<String, FeignClientConfiguration> config = new HashMap<>();
// 默认情况下,Feign客户端不编码斜杠'/'字符,为了改变这一行为,可以将decodeSlash设置为false
private boolean decodeSlash = true;
// Feign客户端配置
public static class FeignClientConfiguration {
private Logger.Level loggerLevel;
private Integer connectTimeout;
private Integer readTimeout;
private Class<Retryer> retryer;
private Class<ErrorDecoder> errorDecoder;
private List<Class<RequestInterceptor>> requestInterceptors;
private Class<ResponseInterceptor> responseInterceptor;
private Map<String, Collection<String>> defaultRequestHeaders;
private Map<String, Collection<String>> defaultQueryParameters;
private Boolean dismiss404;
private Class<Decoder> decoder;
private Class<Encoder> encoder;
private Class<Contract> contract;
private ExceptionPropagationPolicy exceptionPropagationPolicy;
private List<Class<Capability>> capabilities;
private Class<QueryMapEncoder> queryMapEncoder;
private MicrometerProperties micrometer;
private Boolean followRedirects;
private String url;
}
public static class MicrometerProperties {
private Boolean enabled = true;
}
}
@Configuration(proxyBeanMethods = false)
public class FeignClientsConfiguration {
// 注入消息转换器
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
// 注入参数注解处理器
@Autowired(required = false)
private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>();
// 注入Feign的类型转换器
@Autowired(required = false)
private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>();
// 注册Feign的日志打印对象
@Autowired(required = false)
private Logger logger;
// 注入SpringDataWeb的属性配置
@Autowired(required = false)
private SpringDataWebProperties springDataWebProperties;
// 注入FeignClient的属性配置
@Autowired(required = false)
private FeignClientProperties feignClientProperties;
// 注入Feign编码的属性配置
@Autowired(required = false)
private FeignEncoderProperties encoderProperties;
// 注册Feign的解码器,就是将响应体解析成返回值类型
@Bean
@ConditionalOnMissingBean
public Decoder feignDecoder(ObjectProvider<HttpMessageConverterCustomizer> customizers) {
return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(messageConverters, customizers)));
}
// 注册Feign的编码码器,就是将参数解析为请求体
@Bean
@ConditionalOnMissingBean
@ConditionalOnMissingClass("org.springframework.data.domain.Pageable")
public Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider, ObjectProvider<HttpMessageConverterCustomizer> customizers) {
return springEncoder(formWriterProvider, encoderProperties, customizers);
}
// 对jpa分页排序的支持的编码器
// 注册Feign的编码码器,就是将参数解析为请求体
@Bean
@ConditionalOnClass(name = "org.springframework.data.domain.Pageable")
@ConditionalOnMissingBean
public Encoder feignEncoderPageable(ObjectProvider<AbstractFormWriter> formWriterProvider, ObjectProvider<HttpMessageConverterCustomizer> customizers) {
PageableSpringEncoder encoder = new PageableSpringEncoder(springEncoder(formWriterProvider, encoderProperties, customizers));
if (springDataWebProperties != null) {
encoder.setPageParameter(springDataWebProperties.getPageable().getPageParameter());
encoder.setSizeParameter(springDataWebProperties.getPageable().getSizeParameter());
encoder.setSortParameter(springDataWebProperties.getSort().getSortParameter());
}
return encoder;
}
// 对jpa请求参数转换为map的编码器
@Bean
@ConditionalOnClass(name = "org.springframework.data.domain.Pageable")
@ConditionalOnMissingBean
public QueryMapEncoder feignQueryMapEncoderPageable() {
PageableSpringQueryMapEncoder queryMapEncoder = new PageableSpringQueryMapEncoder();
if (springDataWebProperties != null) {
queryMapEncoder.setPageParameter(springDataWebProperties.getPageable().getPageParameter());
queryMapEncoder.setSizeParameter(springDataWebProperties.getPageable().getSizeParameter());
queryMapEncoder.setSortParameter(springDataWebProperties.getSort().getSortParameter());
}
return queryMapEncoder;
}
// Contract 接口定义了如何根据 Java 接口的注解创建请求和解析响应
// Contract 接口是 Feign 的一个核心接口,它可以自定义 Feign 客户端与服务端之间的契约规则,例如支持不同的注解风格、参数传递方式等
// 通过实现自定义的 Contract 接口,可以更灵活地定制 Feign 客户端与服务端之间的通信行为
// 该类负责解析一些注解SpringMVC的注解信息,校验哪些注解是否标注错误,解析方法上的RequestMapping注解,参数上的Param注解等
// 解析到的注解信息,然后交给RequestTemplate
// 例如:
// @CollectionFormat: 集合类型的数据如何传递,CSV,\t,|分割等等
// @RequestMapping解析,@Param,@SpringQueryMap,@QueryMap,@RequestParam处理
// 该类还包含对应注解的参数解析器
@Bean
@ConditionalOnMissingBean
public Contract feignContract(ConversionService feignConversionService) {
boolean decodeSlash = feignClientProperties == null || feignClientProperties.isDecodeSlash();
return new SpringMvcContract(parameterProcessors, feignConversionService, decodeSlash);
}
// 类型转换服务
@Bean
public FormattingConversionService feignConversionService() {
FormattingConversionService conversionService = new DefaultFormattingConversionService();
for (FeignFormatterRegistrar feignFormatterRegistrar : feignFormatterRegistrars) {
feignFormatterRegistrar.registerFormatters(conversionService);
}
return conversionService;
}
// 注册FeignClient的自定义重试机制,默认不重试
@Bean
@ConditionalOnMissingBean
public Retryer feignRetryer() {
return Retryer.NEVER_RETRY;
}
// 注册创建Fiegn日志对象的工厂类
@Bean
@ConditionalOnMissingBean(FeignLoggerFactory.class)
public FeignLoggerFactory feignLoggerFactory() {
return new DefaultFeignLoggerFactory(logger);
}
// 注册FeignClient的自定义配置类
@Bean
@ConditionalOnMissingBean(FeignClientConfigurer.class)
public FeignClientConfigurer feignClientConfigurer() {
return new FeignClientConfigurer() {
};
}
// Spring的编码器,对应POJO以及表单的编码器(就是将参数解析为请求体)
private Encoder springEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider, FeignEncoderProperties encoderProperties, ObjectProvider<HttpMessageConverterCustomizer> customizers) {
AbstractFormWriter formWriter = formWriterProvider.getIfAvailable();
if (formWriter != null) {
return new SpringEncoder(new SpringPojoFormEncoder(formWriter), messageConverters, encoderProperties, customizers);
} else {
return new SpringEncoder(new SpringFormEncoder(), messageConverters, encoderProperties, customizers);
}
}
private class SpringPojoFormEncoder extends SpringFormEncoder {
SpringPojoFormEncoder(AbstractFormWriter formWriter) {
super();
MultipartFormContentProcessor processor = (MultipartFormContentProcessor) getContentProcessor(MULTIPART);
processor.addFirstWriter(formWriter);
}
}
// 注册创建Feign客户端的Feign.Builder的Bean对象,当熔断禁用才会加载
@Configuration(proxyBeanMethods = false)
@Conditional(FeignCircuitBreakerDisabledConditions.class)
protected static class DefaultFeignBuilderConfiguration {
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
public Feign.Builder feignBuilder(Retryer retryer) {
return Feign.builder().retryer(retryer);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(CircuitBreaker.class)
@ConditionalOnProperty("spring.cloud.openfeign.circuitbreaker.enabled")
protected static class CircuitBreakerPresentFeignBuilderConfiguration {
// 根据是否开启熔断来给定创建Feign客户端的Builder对象
// 不支持熔断的FeignBuilder对象
@Bean
@Scope("prototype")
@ConditionalOnMissingBean({Feign.Builder.class, CircuitBreakerFactory.class})
public Feign.Builder defaultFeignBuilder(Retryer retryer) {
return Feign.builder().retryer(retryer);
}
// 支持熔断的FeignBuilder对象
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
@ConditionalOnBean(CircuitBreakerFactory.class)
public Feign.Builder circuitBreakerFeignBuilder() {
return FeignCircuitBreaker.builder();
}
}
// 注册micrometer链路追踪功能
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.cloud.openfeign.micrometer.enabled", matchIfMissing = true)
@ConditionalOnClass({MicrometerObservationCapability.class, MicrometerCapability.class, MeterRegistry.class})
@Conditional(FeignClientMicrometerEnabledCondition.class)
protected static class MicrometerConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(type = "io.micrometer.observation.ObservationRegistry")
public MicrometerObservationCapability micrometerObservationCapability(ObservationRegistry registry) {
return new MicrometerObservationCapability(registry);
}
@Bean
@ConditionalOnBean(type = "io.micrometer.core.instrument.MeterRegistry")
@ConditionalOnMissingBean({MicrometerCapability.class, MicrometerObservationCapability.class})
public MicrometerCapability micrometerCapability(MeterRegistry registry) {
return new MicrometerCapability(registry);
}
}
}
// 创建FeignClient代理对象Bean的类
// 对于每一个FeignClient而言,都会有对应它contextId独立的一个Spring容器,并且真实的Spring容器作为他们的父容器存在
// 如果需要对指定的FeignCliet配置独立的Bean,则再@FeignClient中的configuration属性中配置,获取@EnableFeignClients中的defaultConfiguration配置
public class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware, BeanFactoryAware {
// 接口名称
private Class<?> type;
// @FeignClient的服务名称
// 服务名称,优先级: serviceId > name > value
private String name;
// @FeignClient的url,优先取用@FeignClient的URL,再取用配置属性文件中设置的url,最后使用默认的url,http://服务名
private String url;
// @FeignClient的contextId,如果不存在,则为name
private String contextId;
// @FeignClient的api的基础路径
private String path;
// 是否应该解码404而不是抛出feigexception,默认为false
// 如果为true,404也会返回对应的结果
private boolean dismiss404;
// 是否继承父上下文标识,就是是否允许继承父容器的配置,例如Bean定义,属性
// 说白了就是会不会继承父容器的bean的信息,当前容器找不到会不会从父容器中找Bean
private boolean inheritParentContext = true;
// Spring上下文与Bean工厂
private ApplicationContext applicationContext;
private BeanFactory beanFactory;
// 获取兜底的处理类
private Class<?> fallback = void.class;
private Class<?> fallbackFactory = void.class;
// 请求超时
private int readTimeoutMillis = new Request.Options().readTimeoutMillis();
// 请求连接超时
private int connectTimeoutMillis = new Request.Options().connectTimeoutMillis();
// 是否跟随服务器进行重定向响应,如果为false
// HTTP 客户端将不会自动跟随重定向,而是将重定向响应返回给调用方。这样可以让开发人员有更多的控制权,可以根据需要自行处理重定向逻辑。
private boolean followRedirects = new Request.Options().isFollowRedirects();
// 是否启用客户端刷新功能spring.cloud.openfeign.client.refresh-enabled
// 就是注册refresh作用域的Bean对象
private boolean refreshableClient = false;
// 自定义在FeignBuilderCustomizer,给Feign进行自定义的处理类
private final List<FeignBuilderCustomizer> additionalCustomizers = new ArrayList<>();
// 获取注解的qualifiers属性,该属性是指定@FeignClient的限定名,也就是FeignClient的bean的别名
// 如果没有设置,默认给定为contextId+FeignClient
private String[] qualifiers = new String[]{};
public FeignClientFactoryBean() {
if (LOG.isDebugEnabled()) {
LOG.debug("Creating a FeignClientFactoryBean.");
}
}
// 创建构建FeignClient的Builder对象
protected Feign.Builder feign(FeignClientFactory context) {
// 从Spring容器中获取FeignLoggerFactory类型的Bean,该工厂是用于处理日志打印的
FeignLoggerFactory loggerFactory = this.get(context, FeignLoggerFactory.class);
// 创建Feign的日志打印对象,它封装了不同的日志实现,有Feign自己控制
Logger logger = loggerFactory.create(type);
// 从Spring容器中获取Feign.Builder的Bean
Feign.Builder builder = this.get(context, Feign.Builder.class)
// 设置日志打印对象
.logger(logger)
// 设置编码器,从Spring容器中获取Encoder,就是将参数解析为请求体
.encoder(this.get(context, Encoder.class))
// 设置解码器,从Spring容器中获取Decoder,就是将响应体解码为返回值
.decoder(this.get(context, Decoder.class))
// Contract 接口定义了如何根据 Java 接口的注解创建请求和解析响应
// Contract 接口是 Feign 的一个核心接口,它可以自定义 Feign 客户端与服务端之间的契约规则,例如支持不同的注解风格、参数传递方式等
// 通过实现自定义的 Contract 接口,可以更灵活地定制 Feign 客户端与服务端之间的通信行为
// 该类负责解析一些注解SpringMVC的注解信息,校验哪些注解是否标注错误,解析方法上的RequestMapping注解,参数上的Param注解等
// 解析到的注解信息,然后交给RequestTemplate
// 例如:
// @CollectionFormat: 集合类型的数据如何传递,CSV,\t,|分割等等
// @RequestMapping解析,@Param,@SpringQueryMap,@QueryMap,@RequestParam处理
// 该类还包含对应注解的参数解析器
// 从Spring容器中获取Contract
.contract(this.get(context, Contract.class));
// 配置Builder对象;
this.configureFeign(context, builder);
return builder;
}
// 执行对FeignBuilder进行自定义操作的配置
private void applyBuildCustomizers(FeignClientFactory context, Feign.Builder builder) {
// 从Spring容器中找给Builder自定义的FeignBuilderCustomizer
Map<String, FeignBuilderCustomizer> customizerMap = context.getInstances(contextId, FeignBuilderCustomizer.class);
if (customizerMap != null) {
// 执行所有的FeignBuilderCustomizer,对Builder进行自定义
customizerMap.values()
.stream()
.sorted(AnnotationAwareOrderComparator.INSTANCE)
.forEach(feignBuilderCustomizer -> feignBuilderCustomizer.customize(builder));
}
// 再执行额外添加的FeignBuilderCustomizer
additionalCustomizers.forEach(customizer -> customizer.customize(builder));
}
// 配置Feign的配置信息
protected void configureFeign(FeignClientFactory context, Feign.Builder builder) {
// 从Spring容器中获取Feign客户端的属性配置
FeignClientProperties properties = beanFactory != null ? beanFactory.getBean(FeignClientProperties.class) : applicationContext.getBean(FeignClientProperties.class);
// 从Spring容器中获取Feigh客户端的FeignClientConfigurer配置类接口实现
// 该配置类的作用是开启父容器的配置继承(例如Bean定义等)以及该FeignClient是否是主要的Bean(防止存在多个Bean实例存在歧义的解决方式,默认为true)
FeignClientConfigurer feignClientConfigurer = this.getOptional(context, FeignClientConfigurer.class);
this.setInheritParentContext(feignClientConfigurer.inheritParentConfiguration());
// 如果存在FeignClient的属性配置类,并且启用父上下文的未配置信息
if (properties != null && inheritParentContext) {
// 是否是默认配置优先: 默认为true
// 如果默认配置优先,则先处理自定的配置类,然后再使用配置属性进行覆盖
if (properties.isDefaultToProperties()) {
// 处理自定义Bean对Feign的设置
this.onfigureUsingConfiguration(context, builder);
// 处理属性文件中对Feign配置,该配置为所有Feign客户端默认配置
this.onfigureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
// 处理属性文件中对Feign配置,该配置为指定contextId的Feign客户端
this.onfigureUsingProperties(properties.getConfig().get(contextId), builder);
} else {
// 处理属性文件中对Feign配置,该配置为所有Feign客户端默认配置
this.configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
// 处理属性文件中对Feign配置,该配置为指定contextId的Feign客户端
this.configureUsingProperties(properties.getConfig().get(contextId), builder);
// 处理自定义Bean对Feign的设置
this.configureUsingConfiguration(context, builder);
}
} else {
// 如果没有对Feign进行属性配置
// 则直接处理自定义Bean对Feign的设置
this.configureUsingConfiguration(context, builder);
}
}
// 使用自定义配置类配置Feign
protected void configureUsingConfiguration(FeignClientFactory context, Feign.Builder builder) {
// 从Spring容器中获取Logger.Level的Bean对象,该对象是设置Feign的日志级别
Logger.Level level = this.getInheritedAwareOptional(context, Logger.Level.class);
if (level != null) {
builder.logLevel(level);
}
// 从Spring容器中获取Retryer的Bean对象,该对象是设置重试机制
Retryer retryer = getInheritedAwareOptional(context, Retryer.class);
if (retryer != null) {
builder.retryer(retryer);
}
// 从Spring容器中获取ErrorDecoder的Bean对象,该对象解码会得到一个异常
ErrorDecoder errorDecoder = getInheritedAwareOptional(context, ErrorDecoder.class);
if (errorDecoder != null) {
builder.errorDecoder(errorDecoder);
} else {
// 如果没有ErrorDecoder的Bean,那么获取FeignErrorDecoderFactory的Bean,用于创建ErrorDecoder
FeignErrorDecoderFactory errorDecoderFactory = getOptional(context, FeignErrorDecoderFactory.class);
if (errorDecoderFactory != null) {
ErrorDecoder factoryErrorDecoder = errorDecoderFactory.create(type);
builder.errorDecoder(factoryErrorDecoder);
}
}
// 从Spring容器中获取Request.Options的Bean对象,该对象是设置请求的属性配置
Request.Options options = getInheritedAwareOptional(context, Request.Options.class);
if (options == null) {
// 如果没,根据beanName获取获取Request.Options
// beanName: Request.Options.class.getCanonicalName() + "-" + contextId
options = getOptionsByName(context, contextId);
}
// 如果找到了,保存请求的相关信息
if (options != null) {
builder.options(options);
readTimeoutMillis = options.readTimeoutMillis();
connectTimeoutMillis = options.connectTimeoutMillis();
followRedirects = options.isFollowRedirects();
}
// 从Spring容器中获取处理Feign请求的拦截器RequestInterceptor
Map<String, RequestInterceptor> requestInterceptors = getInheritedAwareInstances(context, RequestInterceptor.class);
if (requestInterceptors != null) {
List<RequestInterceptor> interceptors = new ArrayList<>(requestInterceptors.values());
AnnotationAwareOrderComparator.sort(interceptors);
builder.requestInterceptors(interceptors);
}
// 从Spring容器中获取处理Feign响应的拦截器ResponseInterceptor
ResponseInterceptor responseInterceptor = getInheritedAwareOptional(context, ResponseInterceptor.class);
if (responseInterceptor != null) {
builder.responseInterceptor(responseInterceptor);
}
// 从Spring容器中获取QueryMapEncoder的Bean对象,该对象是用于将请求参数对象转换为map的编码器
QueryMapEncoder queryMapEncoder = getInheritedAwareOptional(context, QueryMapEncoder.class);
if (queryMapEncoder != null) {
builder.queryMapEncoder(queryMapEncoder);
}
// 是否应该解码404而不是抛出feigexception,默认为false
// 如果为true,404也会返回对应的结果
if (dismiss404) {
builder.dismiss404();
}
// 从Spring容器中获取ExceptionPropagationPolicy的Bean对象,该对象是用于设定Feign异常的传播策略
ExceptionPropagationPolicy exceptionPropagationPolicy = getInheritedAwareOptional(context, ExceptionPropagationPolicy.class);
if (exceptionPropagationPolicy != null) {
builder.exceptionPropagationPolicy(exceptionPropagationPolicy);
}
// 从Spring容器中获取Capability的Bean对象,该对象是用于将以上描述的组件进行增强的接口
// 该接口的定义: A enrich (A a){return a;},给你指定参数,让你增强,返回增强后的组件
Map<String, Capability> capabilities = getInheritedAwareInstances(context, Capability.class);
if (capabilities != null) {
capabilities.values().stream().sorted(AnnotationAwareOrderComparator.INSTANCE).forEach(builder::addCapability);
}
}
// 根据配置文件属性对Feign进行配置
protected void configureUsingProperties(FeignClientProperties.FeignClientConfiguration config, Feign.Builder builder) {
if (config == null) {
return;
}
// 设置日志级别
if (config.getLoggerLevel() != null) {
builder.logLevel(config.getLoggerLevel());
}
// 是否启用客户端刷新功能spring.cloud.openfeign.client.refresh-enabled
// 就是注册refresh作用域的Bean对象
if (!refreshableClient) {
// 获取设置的连接超时时间
connectTimeoutMillis = config.getConnectTimeout() != null ? config.getConnectTimeout() : connectTimeoutMillis;
// 获取设置的请求超时时间
readTimeoutMillis = config.getReadTimeout() != null ? config.getReadTimeout() : readTimeoutMillis;
// 是否跟随服务器进行重定向响应,如果为false
// HTTP 客户端将不会自动跟随重定向,而是将重定向响应返回给调用方。这样可以让开发人员有更多的控制权,可以根据需要自行处理重定向逻辑。
followRedirects = config.isFollowRedirects() != null ? config.isFollowRedirects() : followRedirects;
builder.options(new Request.Options(connectTimeoutMillis, TimeUnit.MILLISECONDS, readTimeoutMillis, TimeUnit.MILLISECONDS, followRedirects));
}
// 设置重试机制
if (config.getRetryer() != null) {
Retryer retryer = getOrInstantiate(config.getRetryer());
builder.retryer(retryer);
}
// 设置异常解码器
if (config.getErrorDecoder() != null) {
ErrorDecoder errorDecoder = getOrInstantiate(config.getErrorDecoder());
builder.errorDecoder(errorDecoder);
}
// 设置请求拦截器
if (config.getRequestInterceptors() != null && !config.getRequestInterceptors().isEmpty()) {
for (Class<RequestInterceptor> bean : config.getRequestInterceptors()) {
RequestInterceptor interceptor = getOrInstantiate(bean);
builder.requestInterceptor(interceptor);
}
}
// 设置响应拦截器
if (config.getResponseInterceptor() != null) {
builder.responseInterceptor(getOrInstantiate(config.getResponseInterceptor()));
}
// 设置是否处理404
if (config.getDismiss404() != null) {
if (config.getDismiss404()) {
builder.dismiss404();
}
}
// 设置编码器,就是将参数解析为请求体
if (Objects.nonNull(config.getEncoder())) {
builder.encoder(getOrInstantiate(config.getEncoder()));
}
// 添加默认的请求头
this.addDefaultRequestHeaders(config, builder);
// 添加默认的请求参数
this.addDefaultQueryParams(config, builder);
// 设置解码器,就是将响应体解码为返回值
if (Objects.nonNull(config.getDecoder())) {
builder.decoder(getOrInstantiate(config.getDecoder()));
}
// Contract 接口定义了如何根据 Java 接口的注解创建请求和解析响应
// Contract 接口是 Feign 的一个核心接口,它可以自定义 Feign 客户端与服务端之间的契约规则,例如支持不同的注解风格、参数传递方式等
// 通过实现自定义的 Contract 接口,可以更灵活地定制 Feign 客户端与服务端之间的通信行为
// 该类负责解析一些注解SpringMVC的注解信息,校验哪些注解是否标注错误,解析方法上的RequestMapping注解,参数上的Param注解等
// 解析到的注解信息,然后交给RequestTemplate
// 例如:
// @CollectionFormat: 集合类型的数据如何传递,CSV,\t,|分割等等
// @RequestMapping解析,@Param,@SpringQueryMap,@QueryMap,@RequestParam处理
// 该类还包含对应注解的参数解析器
if (Objects.nonNull(config.getContract())) {
builder.contract(getOrInstantiate(config.getContract()));
}
// 设定Feign异常的传播策略
if (Objects.nonNull(config.getExceptionPropagationPolicy())) {
builder.exceptionPropagationPolicy(config.getExceptionPropagationPolicy());
}
// 设置将以上描述的组件进行增强的接口
// 该接口的定义: A enrich (A a){return a;},给你指定参数,让你增强,返回增强后的组件
if (config.getCapabilities() != null) {
config.getCapabilities().stream().map(this::getOrInstantiate).forEach(builder::addCapability);
}
// 设置将请求参数对象转换为map的编码器
if (config.getQueryMapEncoder() != null) {
builder.queryMapEncoder(this.getOrInstantiate(config.getQueryMapEncoder()));
}
}
// 添加默认的请求参数
private void addDefaultQueryParams(FeignClientProperties.FeignClientConfiguration config, Feign.Builder builder) {
// 获取配置属性中的查询参数
Map<String, Collection<String>> defaultQueryParameters = config.getDefaultQueryParameters();
if (Objects.nonNull(defaultQueryParameters)) {
// 添加一个拦截器,用于添加配置的请求参数
builder.requestInterceptor(requestTemplate -> {
// 获取所有请求参数
Map<String, Collection<String>> queries = requestTemplate.queries();
defaultQueryParameters.keySet().forEach(key -> {
// 将参数设置到requestTemplate中
if (!queries.containsKey(key)) {
requestTemplate.query(key, defaultQueryParameters.get(key));
}
});
});
}
}
// 添加默认的请求头
private void addDefaultRequestHeaders(FeignClientProperties.FeignClientConfiguration config, Feign.Builder builder) {
// 获取配置属性中的请求头
Map<String, Collection<String>> defaultRequestHeaders = config.getDefaultRequestHeaders();
if (Objects.nonNull(defaultRequestHeaders)) {
// 添加一个拦截器,用于添加配置的请求头
builder.requestInterceptor(requestTemplate -> {
// 获取所有的请求头
Map<String, Collection<String>> headers = requestTemplate.headers();
defaultRequestHeaders.keySet().forEach(key -> {
// 将请求头设置到requestTemplate中
if (!headers.containsKey(key)) {
requestTemplate.header(key, defaultRequestHeaders.get(key));
}
});
});
}
}
// 从Spring容器中获取Bean
private <T> T getOrInstantiate(Class<T> tClass) {
return beanFactory != null ? beanFactory.getBean(tClass) : applicationContext.getBean(tClass);
}
// 获取指定contextId对应的Spring容器中指定类型的Bean
protected <T> T get(FeignClientFactory context, Class<T> type) {
T instance = context.getInstance(contextId, type);
if (instance == null) {
throw new IllegalStateException("No bean found of type " + type + " for " + contextId);
}
return instance;
}
protected <T> T getOptional(FeignClientFactory context, Class<T> type) {
return context.getInstance(contextId, type);
}
// 设置支持负载均衡的Client对象
protected <T> T loadBalance(Feign.Builder builder, FeignClientFactory context, HardCodedTarget<T> target) {
/**
* 从指定contextId对应的上下文对象中获取Client类型的Bean,Client是用于提交http请求的客户端
* 同时也会从父容器中找
* {@link feign.Client}
*/
Client client = this.getOptional(context, Client.class);
// 如果存在
if (client != null) {
// 给builder设置
builder.client(client);
// 执行对FeignBuilder进行自定义操作的配置
this.applyBuildCustomizers(context, builder);
// 获取指定contextId对应的Spring容器中Targeter类型的Bean
Targeter targeter = this.get(context, Targeter.class);
// 返回FeignClient的代理对象
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?");
}
// 通过指定名称获取请求操作
protected Request.Options getOptionsByName(FeignClientFactory context, String contextId) {
// 如果不支持客户端刷新,返回null,否则返回对应的实例
if (refreshableClient) {
return context.getInstance(contextId, Request.Options.class.getCanonicalName() + "-" + contextId, Request.Options.class);
}
return null;
}
@OverridegetTarget
public Object getObject() {
// 赶回代理对象
return this. ();
}
public <T> T getTarget() {
// 获取FeignClient的工厂的Bean对象
FeignClientFactory feignClientFactory = beanFactory != null ? beanFactory.getBean(FeignClientFactory.class) : applicationContext.getBean(FeignClientFactory.class);
// 创建FeignClient的Buider对象
Feign.Builder builder = this.feign(feignClientFactory);
// 如果没有在属性配置文件中配置url
if (!StringUtils.hasText(this.url) && !isUrlAvailableInConfig(contextId)) {
if (LOG.isInfoEnabled()) {
LOG.info("For '" + name + "' URL not provided. Will try picking an instance via load-balancing.");
}
// url为服务名称拼接http
if (!name.startsWith("http")) {
this.url = "http://" + name;
} else {
this.url = name;
}
// 添加开头的"/",以及除去结尾的"/"
this.url += cleanPath();
// 创建负载均衡客户端
return (T) this.loadBalance(builder, feignClientFactory, new HardCodedTarget<>(type, name, url));
}
// 如果属性文件中配置了url或者当前给当前FactoryBean设置了了url属性
// 那这样就相当于写死了指定的url,Feign就不会设置负载均衡
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
this.url = "http://" + this.url;
}
// 添加开头的"/",以及除去结尾的"/"
String url = this.url + cleanPath();
/**
* 从指定contextId对应的上下文对象中获取Client类型的Bean,Client是用于提交http请求的客户端
* 同时也会从父容器中找
* {@link feign.Client}
*/
Client client = getOptional(feignClientFactory, Client.class);
if (client != null) {
if (client instanceof FeignBlockingLoadBalancerClient) {
// 不是负载均衡,因为我们配置了指定的url,所以直接获取Client进行操作
client = ((FeignBlockingLoadBalancerClient) client).getDelegate();
}
if (client instanceof RetryableFeignBlockingLoadBalancerClient) {
// 不是负载均衡,因为我们配置了指定的url,所以直接获取Client进行操作
client = ((RetryableFeignBlockingLoadBalancerClient) client).getDelegate();
}
builder.client(client);
}
// 执行对FeignBuilder进行自定义操作的配置
this.applyBuildCustomizers(feignClientFactory, builder);
// 获取指定contextId对应的Spring容器中Targeter类型的Bean
Targeter targeter = this.get(feignClientFactory, Targeter.class);
// 解析目标对象,由该对象描述FeignClient的信息,最终得到Request请求对象
HardCodedTarget<T> target = this.resolveTarget(feignClientFactory, contextId, this.url);
// 返回FeignClient的代理对象
return targeter.target(this, builder, feignClientFactory, target);
}
// 添加开头的"/",以及除去结尾的"/"
private String cleanPath() {
if (path == null) {
return "";
}
String path = this.path.trim();
if (StringUtils.hasLength(path)) {
if (!path.startsWith("/")) {
path = "/" + path;
}
if (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
}
return path;
}
// 解析目标对象,由该对象描述FeignClient的信息,最终得到Request请求对象
private <T> HardCodedTarget<T> resolveTarget(FeignClientFactory context, String contextId, String url) {
// 如果存在url,在@FeignClient中写的url,直接返回HardCodedTarget对象
if (StringUtils.hasText(url)) {
return new HardCodedTarget(type, name, url);
}
// 如果没有在@FeignClient中写的url
// 允许客户端刷新
if (refreshableClient) {
// 获取可刷新的url的Bean
RefreshableUrl refreshableUrl = context.getInstance(contextId, RefreshableUrl.class.getCanonicalName() + "-" + contextId, RefreshableUrl.class);
// 如果存在该Bean,,并且存在url,返回可以刷新的目标对象RefreshableHardCodedTarget
if (Objects.nonNull(refreshableUrl) && StringUtils.hasText(refreshableUrl.getUrl())) {
return new RefreshableHardCodedTarget<>(type, name, refreshableUrl);
}
}
// 如果在@FeignClient中没写的url,也不允许客户端刷新,属性配置也没有配置url,抛出异常
FeignClientProperties.FeignClientConfiguration config = this.findConfigByKey(contextId);
if (Objects.isNull(config) || !StringUtils.hasText(config.getUrl())) {
throw new IllegalStateException("Provide Feign client URL either in @FeignClient() or in config properties.");
}
// 如果存在属性配置url,则返回基于属性的目标对象PropertyBasedTarget
return new PropertyBasedTarget(type, name, config);
}
// 是否在属性文件中配置了url
private boolean isUrlAvailableInConfig(String contextId) {
// 获取属性文件中指定contextId的配置信息
FeignClientProperties.FeignClientConfiguration config = this.findConfigByKey(contextId);
// 是否配置了url信息
return Objects.nonNull(config) && StringUtils.hasText(config.getUrl());
}
/**
* 获取FeignClient的属性配置,从容器中找FeignClientProperties的Bean
* {@link FeignAutoConfiguration}
*/
private FeignClientProperties.FeignClientConfiguration findConfigByKey(String configKey) {
FeignClientProperties properties = beanFactory != null ? beanFactory.getBean(FeignClientProperties.class) : applicationContext.getBean(FeignClientProperties.class);
return properties.getConfig().get(configKey);
}
@Override
public Class<?> getObjectType() {
return type;
}
public boolean isInheritParentContext() {
return inheritParentContext;
}
public void setInheritParentContext(boolean inheritParentContext) {
this.inheritParentContext = inheritParentContext;
}
// 添加给FeignBuilder自定义的类
public void addCustomizer(FeignBuilderCustomizer customizer) {
additionalCustomizers.add(customizer);
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.applicationContext = context;
this.beanFactory = context;
}
}
// 用于描述FeignClient的自定义配置类对象信息
public class FeignClientSpecification implements NamedContextFactory.Specification {
// 情况一: FeignClient的客户端名称(可能是@FeignClient的contextId,value,name,serviceId属性)
// 情况二: @EnableFeignClients注解设置了"defaultConfiguration"默认的配置为了属性,则名称为"default."+标注该注解的类名
private String name;
// 情况一: 标注@FeignClient的接口名
// 情况二: @EnableFeignClients注解设置了"defaultConfiguration"默认的配置为了属性,则类名为"default"
private String className;
// 情况一: @FeignClient注解中的configuration属性配置类
// 情况二: @EnableFeignClients注解中的defaultConfiguration属性配置类
private Class<?>[] configuration;
public FeignClientSpecification(String name, String className, Class<?>[] configuration) {
this.name = name;
this.className = className;
this.configuration = configuration;
}
}
// 创FeignClient的工厂类,该工厂缓存了所有contextId以及它对应的ApplicationContext对象
public class FeignClientFactory extends NamedContextFactory<FeignClientSpecification> {
public FeignClientFactory() {
this(new HashMap<>());
}
public FeignClientFactory(Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers) {
super(FeignClientsConfiguration.class, "spring.cloud.openfeign", "spring.cloud.openfeign.client.name", applicationContextInitializers);
}
public <T> T getInstance(String contextName, String beanName, Class<T> type) {
return this.getContext(contextName).getBean(beanName, type);
}
// 设置作用与FeignClient自定义的ApplicationContextInitializer初始化器,返回一个新工厂
public FeignClientFactory withApplicationContextInitializers(Map<String, Object> applicationContextInitializers) {
Map<String, ApplicationContextInitializer<GenericApplicationContext>> convertedInitializers = new HashMap<>();
applicationContextInitializers
.keySet()
.forEach(contextId -> convertedInitializers.put(contextId, (ApplicationContextInitializer<GenericApplicationContext>) applicationContextInitializers.get(contextId)));
// 返回工厂对象
return new FeignClientFactory(convertedInitializers);
}
}
public abstract class NamedContextFactory<C extends NamedContextFactory.Specification> implements DisposableBean, ApplicationContextAware {
// ApplicationContext初始化器,创建好了ApplicationContext,可以对ApplicationContext进行初始化
// @FeignClient中的contextId -> 对应该从contextId的初始化器
private final Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers;
// 给当前新创建的新上下文设置一套属性,名称为"spring.cloud.openfeign",并且设置一个键值对,key为"spring.cloud.openfeign.client.name",value为FeignClient的contextId
// 要添加到环境对象的MapPropertySource对象的名称,为"spring.cloud.openfeign"
private final String propertySourceName;
// 要添加到环境对象的MapPropertySource对象中的属性名称 "spring.cloud.openfeign.client.name"
private final String propertyName;
// @FeignClient中的contextId -> 对应该context独有的ApplicationContext对象
// 也就是每一个@FeignClient存在一个单独的ApplicationContext
private final Map<String, GenericApplicationContext> contexts = new ConcurrentHashMap<>();
/**
* 注册到Spring容器中的FeignClientSpecification的Bean对象
* {@link FeignClientsRegistrar#registerClientConfiguration}
* {@link FeignClientSpecification}
* <pre>
* key:
* 情况一: FeignClient的客户端名称(可能是@FeignClient的contextId,value,name,serviceId属性)
* 情况二: @EnableFeignClients注解设置了"defaultConfiguration"默认的配置为了属性,则名称为"default."+标注该注解的类名
* value:
* 为key对应的配置类对象的描述信息{@link FeignClientSpecification}
* </pre>
*/
private Map<String, C> configurations = new ConcurrentHashMap<>();
// 父Spring容器,因为每一个FeignClient都会创建一个独有的ApplicationContext,而实际的ApplicationContext则为新创建的父容器
private ApplicationContext parent;
// 默认的配置类型: FeignClientsConfiguration
private Class<?> defaultConfigType;
public NamedContextFactory(Class<?> defaultConfigType, String propertySourceName, String propertyName) {
this(defaultConfigType, propertySourceName, propertyName, new HashMap<>());
}
public NamedContextFactory(Class<?> defaultConfigType, String propertySourceName, String propertyName, Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers) {
this.defaultConfigType = defaultConfigType;
this.propertySourceName = propertySourceName;
this.propertyName = propertyName;
this.applicationContextInitializers = applicationContextInitializers;
}
@Override
public void setApplicationContext(ApplicationContext parent) throws BeansException {
this.parent = parent;
}
public ApplicationContext getParent() {
return parent;
}
/**
* 会将Spring容器中的FeignClientSpecification类型的Bean保存起来
* {@link FeignAutoConfiguration#feignContext}
*/
public void setConfigurations(List<C> configurations) {
for (C client : configurations) {
this.configurations.put(client.getName(), client);
}
}
// 获取所有FeignClient的contextId
public Set<String> getContextNames() {
return new HashSet<>(this.contexts.keySet());
}
// 销毁所有GenericApplicationContext
@Override
public void destroy() {
// 获取所有的FeignClient对应的上下文对象
Collection<GenericApplicationContext> values = this.contexts.values();
for (GenericApplicationContext context : values) {
// 关闭所有容器
context.close();
}
// 清空
this.contexts.clear();
}
// 获取执行contextId对应的GenericApplicationContext对象,如果不存在,则创建一个新的GenericApplicationContext并缓存起来
protected GenericApplicationContext getContext(String name) {
if (!this.contexts.containsKey(name)) {
synchronized (this.contexts) {
// 不存在该contextId对应的上下文对象
if (!this.contexts.containsKey(name)) {
// 创建上下文对象
GenericApplicationContext context = this.createContext(name);
// 缓存
this.contexts.put(name, context);
}
}
}
// 返回该contextId在缓存中的上下文对象
return this.contexts.get(name);
}
// 根据contextId创建对应的上下文对象
public GenericApplicationContext createContext(String name) {
// 创建新的上下文对象
GenericApplicationContext context = this.buildContext(name);
ApplicationContextInitializer<GenericApplicationContext> initializer = applicationContextInitializers.get(name);
// 这个上下文有一个AOT初始化器
if (initializer != null) {
// 执行初始化操作
initializer.initialize(context);
// 刷新容器
context.refresh();
return context;
}
// 注册
registerBeans(name, context);
// 刷新容器
context.refresh();
return context;
}
// 在新创建的容器中注册在@FeignClient注解或者@EnableFeignClients中设置的配置类属性,将他们注册为Bean
public void registerBeans(String name, GenericApplicationContext context) {
Assert.isInstanceOf(AnnotationConfigRegistry.class, context);
AnnotationConfigRegistry registry = (AnnotationConfigRegistry) context;
// 配置每一个FeignClient独有的配置类
// 该contextId(FeignClient)的是否设置了自定义配置类
if (this.configurations.containsKey(name)) {
// 获取到该contextId对应的配置类信息
for (Class<?> configuration : this.configurations.get(name).getConfiguration()) {
// 注册该Bean
registry.register(configuration);
}
}
// 配置所有FeignClient共享的配置类
// 再注册@EnableFeignClients中的defaultConfiguration属性对应的配置类,该配置类可以理解为作为全局的
for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
if (entry.getKey().startsWith("default.")) {
for (Class<?> configuration : entry.getValue().getConfiguration()) {
registry.register(configuration);
}
}
}
// 注册两个Bean,一个解析属性占位符的处理器,一个是当前类的默认配置类型: org.springframework.cloud.openfeign.FeignClientsConfiguration
registry.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType);
}
// 创建新的上下文对象
public GenericApplicationContext buildContext(String name) {
ClassLoader classLoader = getClass().getClassLoader();
GenericApplicationContext context;
// 如果存在父容器,在setAppliction中就已经设置了
// 此时新创建的容器就要使用父容器的Bean的类加载器
if (this.parent != null) {
// 先创建一个新Bean工厂
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 设置当前Bean的类加载器为父容器的Bean的类加载器
if (parent instanceof ConfigurableApplicationContext) {
beanFactory.setBeanClassLoader(((ConfigurableApplicationContext) parent).getBeanFactory().getBeanClassLoader());
} else {
beanFactory.setBeanClassLoader(classLoader);
}
// 创建上下文对象,并且指定Bean工厂
context = AotDetector.useGeneratedArtifacts() ? new GenericApplicationContext(beanFactory) : new AnnotationConfigApplicationContext(beanFactory);
}
// 如果不存在父容器,就不需要使用父容器的Bean的类加载器
else {
context = AotDetector.useGeneratedArtifacts() ? new GenericApplicationContext() : new AnnotationConfigApplicationContext();
}
context.setClassLoader(classLoader);
// 给当前创建的新上下文设置一套属性,名称为"spring.cloud.openfeign",并且设置一个键值对,key为"spring.cloud.openfeign.client.name",value为FeignClient的contextId
context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(this.propertySourceName, Collections.singletonMap(this.propertyName, name)));
if (this.parent != null) {
// 设置父容器
context.setParent(this.parent);
}
// 设置显示名称,为this.getClass().getSimpleName() + "-" + name;
context.setDisplayName(this.generateDisplayName(name));
return context;
}
// 根据contextId获取对应的GenericApplicationContext中指定类型的Bean对象
public <T> T getInstance(String name, Class<T> type) {
GenericApplicationContext context = this.getContext(name);
return context.getBean(type);
}
/**
* 带有名称和配置的描述信息
*/
public interface Specification {
// 获取配置的名称,就是FeignClient的contextId,name,value,serviceId
String getName();
// 该FeignClient的指定的配置类
Class<?>[] getConfiguration();
}
}
// 注册可刷新的Bean,就是该Bean的作用域为refresh,在配置刷新的时候会进行重新创建
// 该Bean为Request.Options,是一个发起请求的配置信息,使用OptionsFactoryBean创建
public class OptionsFactoryBean implements FactoryBean<Request.Options>, ApplicationContextAware {
// Spring上下文对象
private ApplicationContext applicationContext;
// 上下文ID
private String contextId;
// 请求操作配置属性
private Request.Options options;
@Override
public Class<?> getObjectType() {
return Request.Options.class;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public Request.Options getObject() {
if (options != null) {
return options;
}
// 创建新对象,默认值为
// this(connectTimeout:10, connectTimeoutUnit:TimeUnit.SECONDS, readTimeout:60, readTimeoutUnit:TimeUnit.SECONDS, followRedirects:true);
options = new Request.Options();
// 获取FeignClient的配置属性信息
FeignClientProperties properties = applicationContext.getBean(FeignClientProperties.class);
// 使用配置属性中的设置代替Request.Options的默认属性
// this(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true);
// 先后使用对于某个contextId的专属属性文件配置覆盖属性文件的默认配置,再覆盖创建Request.Options默认的配置
// 顺序: 针对contextId的请求属性文件配置 > default的请求属性文件配置 > 默认Request.Options对象的属性配置
options = this.createOptionsWithApplicableValues(properties.getConfig().get(properties.getDefaultConfig()), options);
options = this.createOptionsWithApplicableValues(properties.getConfig().get(contextId), options);
return options;
}
public void setContextId(String contextId) {
this.contextId = contextId;
}
// 使用配置属性中的设置代代替Request.Options的默认属性
// this(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true);
private Request.Options createOptionsWithApplicableValues(FeignClientProperties.FeignClientConfiguration clientConfiguration, Request.Options options) {
if (Objects.isNull(clientConfiguration)) {
return options;
}
int connectTimeoutMillis = Objects.nonNull(clientConfiguration.getConnectTimeout()) ? clientConfiguration.getConnectTimeout() : options.connectTimeoutMillis();
int readTimeoutMillis = Objects.nonNull(clientConfiguration.getReadTimeout()) ? clientConfiguration.getReadTimeout() : options.readTimeoutMillis();
boolean followRedirects = Objects.nonNull(clientConfiguration.isFollowRedirects()) ? clientConfiguration.isFollowRedirects() : options.isFollowRedirects();
return new Request.Options(connectTimeoutMillis, TimeUnit.MILLISECONDS, readTimeoutMillis, TimeUnit.MILLISECONDS, followRedirects);
}
}
// Feign请求的核心对象
public class Request {
// 请求方式
private final HttpMethod httpMethod;
// 请求url
private final String url;
// 请求头
private final Map<String, Collection<String>> headers;
// 请求体
private final Body body;
// 发送请求的模板对象,它负责组装url,请求参数,请求头等一系列请求相关的数据,所以才成为请求模板类
private final RequestTemplate requestTemplate;
// 请求协议
private final ProtocolVersion protocolVersion;
// 请求方法
public enum HttpMethod {
GET, HEAD, POST(true), PUT(true), DELETE, CONNECT, OPTIONS, TRACE, PATCH(true);
private final boolean withBody;
}
// 创建Request对象
public static Request create(HttpMethod httpMethod, String url, Map<String, Collection<String>> headers, Body body, RequestTemplate requestTemplate) {
return new Request(httpMethod, url, headers, body, requestTemplate);
}
// 请求的属性配置
public static class Options {
private final long connectTimeout;
private final TimeUnit connectTimeoutUnit;
private final long readTimeout;
private final TimeUnit readTimeoutUnit;
private final boolean followRedirects;
}
public static class Body implements Serializable {
private transient Charset encoding;
private byte[] data;
}
}
// 对于在配置文件中配置的Feign的url,当配置中心发生改变的时候,当前类(Bean)会重新刷新,得到最新的URL
// 注意: 标注在@FeignClient中的url不会刷新
public class RefreshableUrl {
private final String url;
}
// 创建可以刷新的URL对象(RefreshableUrl)
// 对于在配置文件中配置的Feign的url,当配置中心发生改变的时候,当前类(Bean)会重新刷新,得到最新的URL
// 注意: 标注在@FeignClient中的url不会刷新
public class RefreshableUrlFactoryBean implements FactoryBean<RefreshableUrl>, ApplicationContextAware {
// Spring上下文对象
private ApplicationContext applicationContext;
// 上下文ID
private String contextId;
// 可刷新的URL对象
private RefreshableUrl refreshableUrl;
@Override
public Class<?> getObjectType() {
return RefreshableUrl.class;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public RefreshableUrl getObject() {
if (refreshableUrl != null) {
return refreshableUrl;
}
// 获取属性配置,如果没有配置对应FeignClient的url,则都不需要刷新URL
FeignClientProperties properties = applicationContext.getBean(FeignClientProperties.class);
if (Objects.isNull(properties.getConfig())) {
return new RefreshableUrl(null);
}
FeignClientProperties.FeignClientConfiguration configuration = properties.getConfig().get(contextId);
if (Objects.isNull(configuration) || !StringUtils.hasText(configuration.getUrl())) {
return new RefreshableUrl(null);
}
// 如果配置了,获取最新配置的url
refreshableUrl = new RefreshableUrl(FeignClientsRegistrar.getUrl(configuration.getUrl()));
return refreshableUrl;
}
}
// 构建执行熔断的Feign对象
public final class FeignCircuitBreaker {
private FeignCircuitBreaker() {
throw new IllegalStateException("Don't instantiate a utility class");
}
public static Builder builder() {
return new Builder();
}
public static final class Builder extends Feign.Builder {
// 生成熔断CircuitBreaker的工厂类
private CircuitBreakerFactory circuitBreakerFactory;
// 客户端名称
private String feignClientName;
// 是否启动熔断分组
private boolean circuitBreakerGroupEnabled;
// 熔断名称解析器
private CircuitBreakerNameResolver circuitBreakerNameResolver;
// 创建目标对象
public <T> T target(Target<T> target, T fallback) {
return build(fallback != null ? new FallbackFactory.Default<>(fallback) : null).newInstance(target);
}
// 创建目标对象
public <T> T target(Target<T> target, FallbackFactory<? extends T> fallbackFactory) {
return build(fallbackFactory).newInstance(target);
}
// 创建目标对象
@Override
public <T> T target(Target<T> target) {
return build(null).newInstance(target);
}
public Feign build(final FallbackFactory<?> nullableFallbackFactory) {
// 设置生成InvocationHandler的工厂类,生成FeignCircuitBreakerInvocationHandler带有熔断的InvocationHandler对象
super.invocationHandlerFactory((target, dispatch) ->
new ReflectiveFeign.FeignCircuitBreakerInvocationHandler(
circuitBreakerFactory, feignClientName, target, dispatch, nullableFallbackFactory,
circuitBreakerGroupEnabled, circuitBreakerNameResolver));
/**
* 生成Feign对象
* {@link ReflectiveFeign}
*/
return super.build();
}
}
}
// Feign的最核心类,该对象负责设置Feign相关的绝大部分东西
public abstract class Feign {
// 构建Feign的Builder对象
public static Builder builder() {
return new Builder();
}
// 生成配置的KEY
public static String configKey(Class targetType, Method method) {
StringBuilder builder = new StringBuilder();
builder.append(targetType.getSimpleName());
builder.append('#').append(method.getName()).append('(');
for (Type param : method.getGenericParameterTypes()) {
param = Types.resolve(targetType, targetType, param);
builder.append(Types.getRawType(param).getSimpleName()).append(',');
}
if (method.getParameterTypes().length > 0) {
builder.deleteCharAt(builder.length() - 1);
}
return builder.append(')').toString();
}
// 根据FeignClient的目标对象生成代理对象
public abstract <T> T newInstance(Target<T> target);
// 构建Feign的Builder对象
public static class Builder extends BaseBuilder<Builder> {
// 发送请求的客户端对象,默认使用HttpURLConnection发送请求
// @TODO
private Client client = new Client.Default(null, null);
public <T> T target(Class<T> apiType, String url) {
return target(new HardCodedTarget<>(apiType, url));
}
public <T> T target(Target<T> target) {
Feign feign = this.build();
return feign.newInstance(target);
}
// 构建Feign对象
public Feign build() {
// 增强当前类的字段信息
super.enrich();
// 创建响应的处理器对象,用来处理响应结果
final ResponseHandler responseHandler = new ResponseHandler(logLevel, logger, decoder, errorDecoder, dismiss404, closeAfterDecode, responseInterceptor);
// 创建生成方法处理器的工厂,方法处理器是用来执行方法的
SynchronousMethodHandler.Factory<Object> methodHandlerFactory = new SynchronousMethodHandler.Factory(
client, retryer, requestInterceptors, responseHandler, logger, logLevel, propagationPolicy,
new RequestTemplateFactoryResolver(encoder, queryMapEncoder), options);
// 创建基于反射的Feign对象
return new ReflectiveFeign<>(contract, methodHandlerFactory, invocationHandlerFactory, () -> null);
}
}
}
// 构建Feign对象的Builder对象,内部包含Feing的所有核心组件
public abstract class BaseBuilder<B extends BaseBuilder<B>> {
// 当前Builder对象
private final B thisB;
// 请求拦截器
protected final List<RequestInterceptor> requestInterceptors = new ArrayList<>();
// 响应拦截器 @TODO
protected ResponseInterceptor responseInterceptor = ResponseInterceptor.DEFAULT;
// Feign的日志级别
protected Logger.Level logLevel = Logger.Level.NONE;
// Contract 接口定义了如何根据 Java 接口的注解创建请求和解析响应
// Contract 接口是 Feign 的一个核心接口,它可以自定义 Feign 客户端与服务端之间的契约规则,例如支持不同的注解风格、参数传递方式等
// 通过实现自定义的 Contract 接口,可以更灵活地定制 Feign 客户端与服务端之间的通信行为
// @TODO 看看下面的Default到底做了什么,这些都是Feign的核心组件
protected Contract contract = new Contract.Default();
// 重试机制
protected Retryer retryer = new Retryer.Default();
// 日志对象
protected Logger logger = new NoOpLogger();
// 编码(就是将参数解析为请求体)对象
protected Encoder encoder = new Encoder.Default();
// 解码对象(就是将响应体解码为返回值)
protected Decoder decoder = new Decoder.Default();
// 解码之后是否关闭资源
protected boolean closeAfterDecode = true;
// 对jpa请求参数转换为map的编码器
protected QueryMapEncoder queryMapEncoder = new FieldQueryMapEncoder();
// 异常解码器,该对象解码会得到一个异常对象
protected ErrorDecoder errorDecoder = new ErrorDecoder.Default();
// 请求的配置信息
protected Options options = new Options();
// 创建JDK动态代理中的InvocationHandler的对象
protected InvocationHandlerFactory invocationHandlerFactory = new InvocationHandlerFactory.Default();
// 是否应该解码404而不是抛出feigexception,默认为false
// 如果为true,404也会返回对应的结果
protected boolean dismiss404;
// 该对象是用于设定Feign异常的传播策略
protected ExceptionPropagationPolicy propagationPolicy = NONE;
// 该对象是用于将以上描述的组件进行增强的接口
// 该接口的定义: A enrich (A a){return a;},给你指定参数,让你增强,返回增强后的组件
protected List<Capability> capabilities = new ArrayList<>();
public BaseBuilder() {
thisB = (B) this;
}
// 增强当前类的字段信息
public B enrich() {
// 如果不存在增强器,不处理
if (capabilities.isEmpty()) {
return thisB;
}
// 获取到当前类的所有字段信息
this.getFieldsToEnrich().forEach(field -> {
field.setAccessible(true);
// 获取原来的值
final Object originalValue = field.get(thisB);
// 增强的值
final Object enriched;
// 如果是List
if (originalValue instanceof List) {
// 获取到泛型信息
Type ownerType = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
// 对List的每一个元素进行增强
enriched = ((List) originalValue).stream()
.map(value -> Capability.enrich(value, (Class<?>) ownerType, capabilities))
.collect(Collectors.toList());
} else {
// 单独对某个字段增强,方法定义: A aa(A a){ return a;}
enriched = Capability.enrich(originalValue, field.getType(), capabilities);
}
// 将字段变成增强后的字段
field.set(thisB, enriched);
});
return thisB;
}
// 获取需要被增强的字段
public List<Field> getFieldsToEnrich() {
return Util.allFields(getClass())
.stream()
.filter(field -> !field.isSynthetic())
.filter(field -> !Objects.equals(field.getName(), "capabilities"))
.filter(field -> !Objects.equals(field.getName(), "thisB"))
.filter(field -> !field.getType().isPrimitive())
.filter(field -> !field.getType().isEnum())
.collect(Collectors.toList());
}
}
// 默认的创建FeignClient的代理对象,不支持熔断
public class DefaultTargeter implements Targeter {
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignClientFactory context, Target.HardCodedTarget<T> target) {
return feign.target(target);
}
}
// 创建支持熔断的FeignClient代理对象
public class FeignCircuitBreakerTargeter implements Targeter {
private final CircuitBreakerFactory circuitBreakerFactory;
private final boolean circuitBreakerGroupEnabled;
private final CircuitBreakerNameResolver circuitBreakerNameResolver;
public FeignCircuitBreakerTargeter(CircuitBreakerFactory circuitBreakerFactory, boolean circuitBreakerGroupEnabled, CircuitBreakerNameResolver circuitBreakerNameResolver) {
this.circuitBreakerFactory = circuitBreakerFactory;
this.circuitBreakerGroupEnabled = circuitBreakerGroupEnabled;
this.circuitBreakerNameResolver = circuitBreakerNameResolver;
}
// 创建代理对象
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignClientFactory context, Target.HardCodedTarget<T> target) {
// 如果feignBuilder不是FeignCircuitBreaker.Builder,执行执行builder的创建对象的逻辑
if (!(feign instanceof FeignCircuitBreaker.Builder builder)) {
return feign.target(target);
}
// 获取服务名称
String name = !StringUtils.hasText(factory.getContextId()) ? factory.getName() : factory.getContextId();
// 获取兜底方法
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);
}
// 没有设置兜底方法,直接创建代理对象
return this.builder(name, builder).target(target);
}
private <T> T targetWithFallbackFactory(String feignClientName, FeignClientFactory context, Target.HardCodedTarget<T> target, FeignCircuitBreaker.Builder builder, Class<?> fallbackFactoryClass) {
// 从Spring上下文中获取该FeignClient的兜底对象FallbackFactory
FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>) this.getFromContext("fallbackFactory", feignClientName, context, fallbackFactoryClass, FallbackFactory.class);
// 构建FeignClient的代理对象
FeignCircuitBreaker.Builder b = this.builder(feignClientName, builder);
return b.target(target, fallbackFactory);
}
private <T> T targetWithFallback(String feignClientName, FeignClientFactory context, Target.HardCodedTarget<T> target, FeignCircuitBreaker.Builder builder, Class<?> fallback) {
// 从Spring上下文中获取该FeignClient的兜底对象fallbackI
T fallbackInstance = this.getFromContext("fallback", feignClientName, context, fallback, target.type());
// 构建FeignClient的代理对象
FeignCircuitBreaker.Builder b = this.builder(feignClientName, builder);
// 构建FeignClient的代理对象
return b.target(target, fallbackInstance);
}
// 从上下文对象中获取兜底的实现
private <T> T getFromContext(String fallbackMechanism, String feignClientName, FeignClientFactory context, Class<?> beanType, Class<T> targetType) {
// 该对象必须时一个Bean对象
Object fallbackInstance = context.getInstance(feignClientName, beanType);
if (fallbackInstance == null) {
throw new IllegalStateException(String.format("No " + fallbackMechanism + " instance of type %s found for feign client %s", beanType, feignClientName));
}
// 如果兜底的实现Bean是一个factoryBean
if (fallbackInstance instanceof FactoryBean<?> factoryBean) {
try {
fallbackInstance = factoryBean.getObject();
} catch (Exception e) {
throw new IllegalStateException(fallbackMechanism + " create fail", e);
}
// 如果该FactoryBean获取的Bean对象与注解规定的类型不一样,抛出异常
if (!targetType.isAssignableFrom(fallbackInstance.getClass())) {
throw new IllegalStateException(String.format("Incompatible " + fallbackMechanism + " instance. Fallback/fallbackFactory of type %s is not assignable to %s for feign client %s", fallbackInstance.getClass(), targetType, feignClientName));
}
} else {
// 如果该Bean对象与注解规定的类型不一样,抛出异常
if (!targetType.isAssignableFrom(beanType)) {
throw new IllegalStateException(String.format("Incompatible " + fallbackMechanism + " instance. Fallback/fallbackFactory of type %s is not assignable to %s for feign client %s", beanType, targetType, feignClientName));
}
}
// 返回兜底的Bean对象
return (T) fallbackInstance;
}
private FeignCircuitBreaker.Builder builder(String feignClientName, FeignCircuitBreaker.Builder builder) {
// 设置Feign相关的属性信息
return builder.circuitBreakerFactory(circuitBreakerFactory)
.feignClientName(feignClientName)
.circuitBreakerGroupEnabled(circuitBreakerGroupEnabled)
.circuitBreakerNameResolver(circuitBreakerNameResolver);
}
}
// 基于反射执行的Feign对象
public class ReflectiveFeign<C> extends Feign {
// 用于将方法转换为方法处理器的对象
private final ParseHandlersByName<C> targetToHandlersByName;
// 创建代理对象InvocationHandler的工厂类
private final InvocationHandlerFactory factory;
// 异步上下文的提供者,默认为空实现,不提供任何上下文信息
private final AsyncContextSupplier<C> defaultContextSupplier;
public ReflectiveFeign(Contract contract, SynchronousMethodHandler.Factory<C> methodHandlerFactory, InvocationHandlerFactory invocationHandlerFactory, AsyncContextSupplier<C> defaultContextSupplier) {
this.targetToHandlersByName = new ParseHandlersByName<C>(contract, methodHandlerFactory);
this.factory = invocationHandlerFactory;
this.defaultContextSupplier = defaultContextSupplier;
}
// 创建FeignClient的代理对象
public <T> T newInstance(Target<T> target) {
return newInstance(target, defaultContextSupplier.newContext());
}
// 创建FeignClient的代理对象
public <T> T newInstance(Target<T> target, C requestContext) {
// 校验FeignClient的合法性
TargetSpecificationVerifier.verify(target);
// 用于将方法转换为方法处理器的对象
Map<Method, SynchronousMethodHandler> methodToHandler = targetToHandlersByName.apply(target, requestContext);
/**
* 创建代理对象的InvocationHandler
* {@link FeignInvocationHandler}
*/
InvocationHandler handler = factory.create(target, methodToHandler);
// 创建FeignClient接口的代理对象
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, handler);
// 找出所有的默认方法
for (SynchronousMethodHandler methodHandler : methodToHandler.values()) {
if (methodHandler instanceof DefaultMethodHandler) {
// 将默认方法绑定到代理对象中
((DefaultMethodHandler) methodHandler).bindTo(proxy);
}
}
return proxy;
}
// 普通代理对象的处理器
public static class FeignInvocationHandler implements InvocationHandler {
// 目标对象信息
private final Target target;
// 该目标对象对应的所有方法以及方法对应的执行器
private final Map<Method, SynchronousMethodHandler> dispatch;
FeignInvocationHandler(Target target, Map<Method, SynchronousMethodHandler> 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 {
/**
* 获取到方法执行器,指定方法的invoke
* {@link SynchronousMethodHandler#invoke(Object[])}
*/
return dispatch.get(method).invoke(args);
}
}
// 执行熔断的代理对象处理器
public static class FeignCircuitBreakerInvocationHandler implements InvocationHandler {
// 创建熔断器的工厂类
private final CircuitBreakerFactory factory;
// 客户端名称
private final String feignClientName;
// 目标对象
private final Target<?> target;
// 目标对象的方法->方法执行器的映射
private final Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;
// 兜底的工厂类
private final FallbackFactory<?> nullableFallbackFactory;
// 原方法->兜底的方法一一对应
private final Map<Method, Method> fallbackMethodMap;
// 是否开启了分组熔断
private final boolean circuitBreakerGroupEnabled;
// 熔断名称解析器
private final CircuitBreakerNameResolver circuitBreakerNameResolver;
public FeignCircuitBreakerInvocationHandler(CircuitBreakerFactory factory, String feignClientName, Target<?> target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch, FallbackFactory<?> nullableFallbackFactory,
boolean circuitBreakerGroupEnabled, CircuitBreakerNameResolver circuitBreakerNameResolver) {
this.factory = factory;
this.feignClientName = feignClientName;
this.target = checkNotNull(target, "target");
this.dispatch = checkNotNull(dispatch, "dispatch");
this.fallbackMethodMap = toFallbackMethod(dispatch);
this.nullableFallbackFactory = nullableFallbackFactory;
this.circuitBreakerGroupEnabled = circuitBreakerGroupEnabled;
this.circuitBreakerNameResolver = circuitBreakerNameResolver;
}
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) {
// 解析熔断的名称
String circuitName = circuitBreakerNameResolver.resolveCircuitBreakerName(feignClientName, target, method);
// 使用熔断器的工厂创建熔断处理器
CircuitBreaker circuitBreaker = circuitBreakerGroupEnabled ? factory.create(circuitName, feignClientName) : factory.create(circuitName);
// 将目标方法的执行对象包装为Supplier
Supplier<Object> supplier = this.asSupplier(method, args);
if (this.nullableFallbackFactory != null) {
// 创建兜底的回调函数,出现异常的时候进行回调
Function<Throwable, Object> fallbackFunction = throwable -> {
Object fallback = this.nullableFallbackFactory.create(throwable);
try {
// 获取兜底方法执行,使用兜底回调类执行兜底方法
return this.fallbackMethodMap.get(method).invoke(fallback, args);
} catch (Exception exception) {
unwrapAndRethrow(exception);
}
return null;
};
// 使用熔断器的实现执行目标方法,执行失败回调兜底逻辑
// 实现: Resilience4JCircuitBreaker
return circuitBreaker.run(supplier, fallbackFunction);
}
// 使用熔断器的实现执行目标方法,如果没有兜底逻辑,抛出异常
// 实现: Resilience4JCircuitBreaker
return circuitBreaker.run(supplier);
}
// 将目标方法的执行对象包装为Supplier
private Supplier<Object> asSupplier(final Method method, final Object[] args) {
// 获取请求属性对象
final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
// 获取当前线程
final Thread caller = Thread.currentThread();
return () -> {
// 是否是异步的
boolean isAsync = caller != Thread.currentThread();
try {
// 如果是异步的,则将请求属性对象传递到下一个线程
if (isAsync) {
RequestContextHolder.setRequestAttributes(requestAttributes);
}
/**
* 发送请求,执行目标方法
* {@link SynchronousMethodHandler#invoke(Object[])}
*/
return dispatch.get(method).invoke(args);
} catch (RuntimeException throwable) {
throw throwable;
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
} finally {
// 重置请求属性
if (isAsync) {
RequestContextHolder.resetRequestAttributes();
}
}
};
}
}
// 用于将方法转换为方法处理器的对象
private static final class ParseHandlersByName<C> {
// Contract 接口定义了如何根据 Java 接口的注解创建请求和解析响应
// Contract 接口是 Feign 的一个核心接口,它可以自定义 Feign 客户端与服务端之间的契约规则,例如支持不同的注解风格、参数传递方式等
// 通过实现自定义的 Contract 接口,可以更灵活地定制 Feign 客户端与服务端之间的通信行为
private final Contract contract;
// 创建MethodHandler对象的工厂,MethodHandler是用于执行目标方法的对象
private final SynchronousMethodHandler.Factory<C> factory;
public ParseHandlersByName(Contract contract, SynchronousMethodHandler.Factory<C> factory) {
this.contract = contract;
this.factory = factory;
}
public Map<Method, SynchronousMethodHandler> apply(Target target, C requestContext) {
final Map<Method, SynchronousMethodHandler> result = new LinkedHashMap<>();
// 解析目标FeignClient接口的方法元数据
final List<MethodMetadata> metadataList = contract.parseAndValidateMetadata(target.type());
// 遍历所有的方法元数据
for (MethodMetadata md : metadataList) {
final Method method = md.method();
// 忽略Object中的方法
if (method.getDeclaringClass() == Object.class) {
continue;
}
// 创建MethodHandler对象
final SynchronousMethodHandler handler = this.createMethodHandler(target, md, requestContext);
// 保存method->方法处理器的映射关系
result.put(method, handler);
}
// 如果FeignClient中包含默认方法,则使用默认的方法处理器处理
for (Method method : target.type().getMethods()) {
if (Util.isDefault(method)) {
final MethodHandler handler = new DefaultMethodHandler(method);
result.put(method, handler);
}
}
return result;
}
// 创建MethodHandler对象
private SynchronousMethodHandler createMethodHandler(Target<?> target, MethodMetadata md, C requestContext) {
// 当前方法是否被标记了忽略
if (md.isIgnored()) {
return args -> {
throw new IllegalStateException(md.configKey() + " is not a method handled by feign");
};
}
// 使用MethodHandler工厂创建MethodHandler对象
return factory.create(target, md, requestContext);
}
}
// 目标FeignClient接口的校验器
// @TODO 待整理,注意事项
public static class TargetSpecificationVerifier {
// 验证目标接口
public static <T> void verify(Target<T> target) {
Class<T> type = target.type();
// 如果@FeignClient不是接口,抛出异常
if (!type.isInterface()) {
throw new IllegalArgumentException("Type must be an interface: " + type);
}
// 遍历所有的方法
for (final Method m : type.getMethods()) {
// 获取返回类型
final Class<?> retType = m.getReturnType();
// 如果不是CompletableFuture,不需要校验
if (!CompletableFuture.class.isAssignableFrom(retType)) {
continue;
}
// 如果不是CompletableFuture,抛出异常,只支持CompletableFuture处理
if (retType != CompletableFuture.class) {
throw new IllegalArgumentException("Method return type is not CompleteableFuture: " + getFullMethodName(type, retType, m));
}
// 获取CompletableFuture的泛型类型
final Type genRetType = m.getGenericReturnType();
// 如果没有获取到泛型,抛出异常
if (!(genRetType instanceof ParameterizedType)) {
throw new IllegalArgumentException("Method return type is not parameterized: " + getFullMethodName(type, genRetType, m));
}
// 如果泛型信息是WildcardType(统配符)类型,也抛出异常
if (((ParameterizedType) genRetType).getActualTypeArguments()[0] instanceof WildcardType) {
throw new IllegalArgumentException("Wildcards are not supported for return-type parameters: " + getFullMethodName(type, genRetType, m));
}
}
}
private static String getFullMethodName(Class<?> type, Type retType, Method m) {
return retType.getTypeName() + " " + type.toGenericString() + "." + m.getName();
}
}
}
// 同步的方法处理器,还有异步的方法处理器
public class SynchronousMethodHandler implements SynchronousMethodHandler {
// 方法的元数据
private final MethodMetadata metadata;
// FeignClient目标接口对象
private final Target<?> target;
// 发送请求的客户端对象
private final Client client;
// 重试机制
private final Retryer retryer;
// 请求拦截器
private final List<RequestInterceptor> requestInterceptors;
// 日志对象
private final Logger logger;
// 日志级别对象
private final Logger.Level logLevel;
// 创建RequestTemplate的工厂
private final RequestTemplate.Factory buildTemplateFromArgs;
// 请求配置信息
private final Options options;
// 异常的传播策略
private final ExceptionPropagationPolicy propagationPolicy;
// 响应处理器
private final ResponseHandler responseHandler;
private SynchronousMethodHandler(Target<?> target, Client client, Retryer retryer,
List<RequestInterceptor> requestInterceptors,
Logger logger, Logger.Level logLevel, MethodMetadata metadata,
RequestTemplate.Factory buildTemplateFromArgs, Options options,
ResponseHandler responseHandler, ExceptionPropagationPolicy propagationPolicy) {
this.target = checkNotNull(target, "target");
this.client = checkNotNull(client, "client for %s", target);
this.retryer = checkNotNull(retryer, "retryer for %s", target);
this.requestInterceptors = checkNotNull(requestInterceptors, "requestInterceptors for %s", target);
this.logger = checkNotNull(logger, "logger for %s", target);
this.logLevel = checkNotNull(logLevel, "logLevel for %s", target);
this.metadata = checkNotNull(metadata, "metadata for %s", target);
this.buildTemplateFromArgs = checkNotNull(buildTemplateFromArgs, "metadata for %s", target);
this.options = checkNotNull(options, "options for %s", target);
this.propagationPolicy = propagationPolicy;
this.responseHandler = responseHandler;
}
// 执行目标方法
@Override
public Object invoke(Object[] argv) throws Throwable {
// 生成RequestTemplate请求模板对象
RequestTemplate template = buildTemplateFromArgs.create(argv);
// 查找请求配置Options对象
Options options = this.findOptions(argv);
// 重试机制
Retryer retryer = this.retryer.clone();
// 死循环是为了满足重试机制
while (true) {
try {
// 执行并解码,因为是while(true),只要不返回,则会一直重试
return this.executeAndDecode(template, options);
}
// 处理请求失败,开始重试
catch (RetryableException e) {
try {
// 记录重试信息,保存重试次数,如果还是未重试成功,继续抛出异常
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
Throwable cause = th.getCause();
if (propagationPolicy == UNWRAP && cause != null) {
throw cause;
} else {
throw th;
}
}
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}
/**
* 发送请求并解码处理响应
*
* @param template 请求的模板对象
* @param options 请求的配置信息
*/
public Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
// 根据请求模板对象创建最终的请求对象
Request request = this.targetRequest(template);
// 打印日志请求信息
if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}
// 响应对象
Response response;
long start = System.nanoTime();
try {
// 发送http客户端发送http请求
response = client.execute(request, options);
// 给当前response设置关于请求的数据
response = response.toBuilder()
.request(request)
.requestTemplate(template)
.build();
} catch (IOException e) {
// 打印异常日志
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
}
// 抛出RetryableException异常
throw errorExecuting(request, e);
}
// 执行结束时间
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
// 使用响应处理器处理响应结果
return responseHandler.handleResponse(metadata.configKey(), response, metadata.returnType(), elapsedTime);
}
// 获取运行的时间
public long elapsedTime(long start) {
return TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
}
// 创建核心的请求对象
public Request targetRequest(RequestTemplate template) {
// 执行所有的请求拦截器
for (RequestInterceptor interceptor : requestInterceptors) {
interceptor.apply(template);
}
// 根据请求模板对象RequestTemplate创建核心的Request请求对象
return target.apply(template);
}
// 查找Options对象
public Options findOptions(Object[] argv) {
// 当存在参数,则获取参数中的Options对象,如果参数不存在获取其他情况,则返回当前类指定了Options对象
if (argv == null || argv.length == 0) {
return this.options;
}
return Stream.of(argv).filter(Options.class::isInstance).map(Options.class::cast).findFirst().orElse(this.options);
}
public static class Factory implements SynchronousMethodHandler.Factory<Object> {
private final Client client;
private final Retryer retryer;
private final List<RequestInterceptor> requestInterceptors;
private final ResponseHandler responseHandler;
private final Logger logger;
private final Logger.Level logLevel;
private final ExceptionPropagationPolicy propagationPolicy;
private final RequestTemplateFactoryResolver requestTemplateFactoryResolver;
private final Options options;
public SynchronousMethodHandler create(Target<?> target, MethodMetadata md, Object requestContext) {
// 根据方法元数据信息,解析未一个生成RequestTemplate模板的工厂对象,因为方法,注解信息都可以作为模板
final RequestTemplate.Factory buildTemplateFromArgs = requestTemplateFactoryResolver.resolve(target, md);
// 创建方法执行的处理器
return new SynchronousMethodHandler(target, client, retryer, requestInterceptors, logger, logLevel, md, buildTemplateFromArgs, options, responseHandler, propagationPolicy);
}
}
}
SpringCloud中@EnableFeignClients和FeignClient的源码解析
最新推荐文章于 2025-02-21 16:40:04 发布