SpringCloud中@EnableFeignClients和FeignClient的源码解析

// 官网地址: 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);

        }
    }
}

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值