美文网首页
spring boot Open Feign 客户端加载过程

spring boot Open Feign 客户端加载过程

作者: 草祭木初 | 来源:发表于2021-03-24 10:41 被阅读0次

    关于Fegin,可以学习下面的文章

    pmo引入
    如果要跑起来的话,还需要consul 和 loadbalancer(Eureka,Ribbon的替代)

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
                <version>3.0.2</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-consul-discovery</artifactId>
                <version>3.0.2</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-loadbalancer</artifactId>
                <version>3.0.2</version>
            </dependency>
    

    spring boot 引入

    @SpringBootApplication
    @EnableFeignClients
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    
    }
    

    @EnableFeignClients

    用了@Import({FeignClientsRegistrar.class})
    参照spring boot Appollo加载过程

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE})
    @Documented
    @Import({FeignClientsRegistrar.class})
    public @interface EnableFeignClients {
        String[] value() default {};
    
        String[] basePackages() default {};
    
        Class<?>[] basePackageClasses() default {};
    
        Class<?>[] defaultConfiguration() default {};
    
        Class<?>[] clients() default {};
    }
    

    FeignClientsRegistrar

    实现了3个接口

    • ImportBeanDefinitionRegistrar:主要是这个,重写了它的registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry)接口
    • ResourceLoaderAware:注入ResourceLoader
    • EnvironmentAware:注入Environment
    class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware { 
      public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            // 注册默认配置
            this.registerDefaultConfiguration(metadata, registry);
            // 注册客户端
            this.registerFeignClients(metadata, registry);
        }
    }
    

    注册默认配置

      private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            Map<String, Object> defaultAttrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
            // defaultConfiguration 这个属性一定有,默认空数组
            if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
                String name;
                // 是否有内部类
                if (metadata.hasEnclosingClass()) {
                    name = "default." + metadata.getEnclosingClassName();
                } else {
                    name = "default." + metadata.getClassName();
                }
                // 注册默认的配置类,也可以通过配置文件,修改默认配置信息
                this.registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration"));
            }
    
        }
    
        private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
            // 向spring 容器注册一个Bean:FeignClientSpecification
            // 构造函数包含两个参数
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
            builder.addConstructorArgValue(name);
            builder.addConstructorArgValue(configuration);
            registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(), builder.getBeanDefinition());
        }
    

    FeignClientSpecification

    实现了:Specification的getConfiguration方法
    Specification 是 NamedContextFactory类的内部接口
    具体的流程后面再说,先看下它的定义,很简单

    class FeignClientSpecification implements Specification {
        private String name;
        private Class<?>[] configuration;
    
        FeignClientSpecification() {
        }
    
        FeignClientSpecification(String name, Class<?>[] configuration) {
            this.name = name;
            this.configuration = configuration;
        }
    
        。。。
    
        public Class<?>[] getConfiguration() {
            return this.configuration;
        }
    
        。。。
    }
    

    注册客户端

        public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet();
            Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
            Class<?>[] clients = attrs == null ? null : (Class[])((Class[])attrs.get("clients"));
    
            // 是否通过 @EnableFeignClients 的clients 配置了 客户端类
            if (clients != null && clients.length != 0) {
                Class[] var12 = clients;
                int var14 = clients.length;
    
                for(int var16 = 0; var16 < var14; ++var16) {
                    Class<?> clazz = var12[var16];
                    candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz));
                }
            } else {
                // 通过扫描来FeignClient注解找到FeignClients
                ClassPathScanningCandidateComponentProvider scanner = this.getScanner();
                scanner.setResourceLoader(this.resourceLoader);
                scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));
                Set<String> basePackages = this.getBasePackages(metadata);
                Iterator var8 = basePackages.iterator();
    
                while(var8.hasNext()) {
                    String basePackage = (String)var8.next();
                    // 扫描指定的包
                    candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
                }
            }
    
            Iterator var13 = candidateComponents.iterator();
    
            while(var13.hasNext()) {
                BeanDefinition candidateComponent = (BeanDefinition)var13.next();
                if (candidateComponent instanceof AnnotatedBeanDefinition) {
                    AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition)candidateComponent;
                    AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
                    Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface");
                    Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
                    String name = this.getClientName(attributes);
                    // 注册配置类, @FeignClient的configuration 属性指定的类
                    this.registerClientConfiguration(registry, name, attributes.get("configuration"));
                    // 注册客户端类
                    this.registerFeignClient(registry, annotationMetadata, attributes);
                }
            }
    
        }
    
        private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
            String className = annotationMetadata.getClassName();
            Class clazz = ClassUtils.resolveClassName(className, (ClassLoader)null);
            ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory ? (ConfigurableBeanFactory)registry : null;
            String contextId = this.getContextId(beanFactory, attributes);
            String name = this.getName(attributes);
            // 这里有个FactoryBean不过这边是主动new的不是,让spring容器管理
            FeignClientFactoryBean factoryBean = new FeignClientFactoryBean();
            factoryBean.setBeanFactory(beanFactory);
            factoryBean.setName(name);
            factoryBean.setContextId(contextId);
            factoryBean.setType(clazz);
            BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> {
                factoryBean.setUrl(this.getUrl(beanFactory, attributes));
                factoryBean.setPath(this.getPath(beanFactory, attributes));
                factoryBean.setDecode404(Boolean.parseBoolean(String.valueOf(attributes.get("decode404"))));
                Object fallback = attributes.get("fallback");
                // 是否定义了熔断处理类
                if (fallback != null) {
                    factoryBean.setFallback(fallback instanceof Class ? (Class)fallback : ClassUtils.resolveClassName(fallback.toString(), (ClassLoader)null));
                }
    
                Object fallbackFactory = attributes.get("fallbackFactory");
                if (fallbackFactory != null) {
                    factoryBean.setFallbackFactory(fallbackFactory instanceof Class ? (Class)fallbackFactory : ClassUtils.resolveClassName(fallbackFactory.toString(), (ClassLoader)null));
                }
                // 真正的创建 FeginClient
                return factoryBean.getObject();
            });
            // 通过set方法注入
            definition.setAutowireMode(2);
            // 延迟初始化,用到的时候 才实例化
            definition.setLazyInit(true);
            this.validate(attributes);
            AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
            beanDefinition.setAttribute("factoryBeanObjectType", className);
            beanDefinition.setAttribute("feignClientsRegistrarFactoryBean", factoryBean);
            boolean primary = (Boolean)attributes.get("primary");
            beanDefinition.setPrimary(primary);
            String[] qualifiers = this.getQualifiers(attributes);
            if (ObjectUtils.isEmpty(qualifiers)) {
                qualifiers = new String[]{contextId + "FeignClient"};
            }
    
            BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
            // 将客户端Bean定义注册到spring容器
            BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
        }
    

    FeignClientFactoryBean

    实现了:

    • FactoryBean,这个接口的作用是,当spring创建实现了FactoryBean接口的Bean时,当你将这个类型注入到其他对象时,实际上返回的是getObject方法返回的对象,返回的类型是getObjectType返回的类型
    • InitializingBean:spring生命周期接口,构造函数调用完,调用
    • ApplicationContextAware:注入ApplicationContext
    • BeanFactoryAware:注入BeanFactory
    public class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware, BeanFactoryAware {
      protected <T> T loadBalance(Builder builder, FeignContext context, HardCodedTarget<T> target) {
            Client client = (Client)this.getOptional(context, Client.class);
            if (client != null) {
                builder.client(client);
                Targeter targeter = (Targeter)this.get(context, Targeter.class);
                return targeter.target(this, builder, context, target);
            } else {
                throw new IllegalStateException("No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?");
            }
        }
        public Object getObject() {
            return this.getTarget();
        }
    
        <T> T getTarget() {
            FeignContext context = this.beanFactory != null ? (FeignContext)this.beanFactory.getBean(FeignContext.class) : (FeignContext)this.applicationContext.getBean(FeignContext.class);
            Builder builder = this.feign(context);
            if (!StringUtils.hasText(this.url)) {
                // 不设定url时
                if (!this.name.startsWith("http")) {
                    this.url = "http://" + this.name;
                } else {
                    this.url = this.name;
                }
    
                this.url = this.url + this.cleanPath();
                return this.loadBalance(builder, context, new HardCodedTarget(this.type, this.name, this.url));
            } else {
                // 设定url时
                if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
                    this.url = "http://" + this.url;
                }
    
                String url = this.url + this.cleanPath();
                Client client = (Client)this.getOptional(context, Client.class);
                if (client != null) {
                    if (client instanceof FeignBlockingLoadBalancerClient) {
                        client = ((FeignBlockingLoadBalancerClient)client).getDelegate();
                    }
    
                    if (client instanceof RetryableFeignBlockingLoadBalancerClient) {
                        client = ((RetryableFeignBlockingLoadBalancerClient)client).getDelegate();
                    }
    
                    builder.client(client);
                }
    
                Targeter targeter = (Targeter)this.get(context, Targeter.class);
                return targeter.target(this, builder, context, new HardCodedTarget(this.type, this.name, url));
            }
        }
    }
    

    这里有两个问题一个Client,一个Targeter

    先看Client
    所以无论走 if 还是 else 都是从context里取到Client
    然后用builder.client创建

    不指定url,用name到注册中心取地址,走负载均衡
    指定url的时候走else,直接访问url,不走负载均衡

    请注意这句,最终返回的对象,是根据Client造出来的

    Client client = (Client)this.getOptional(context, Client.class);
    
      protected <T> T getOptional(FeignContext context, Class<T> type) {
            return context.getInstance(this.contextId, type);
        }
    
      public <T> T getInstance(String name, Class<T> type) {
            AnnotationConfigApplicationContext context = this.getContext(name);
    
            try {
                return context.getBean(type);
            } catch (NoSuchBeanDefinitionException var5) {
                return null;
            }
        }
    

    可以看到 Client 是从AnnotationConfigApplicationContext 里取出来的

    但我们并没有配置或创建这个Bean
    所以只有一种可能 通过@Configuration 创建出来的
    找一下
    spring.factories

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    org.springframework.cloud.openfeign.hateoas.FeignHalAutoConfiguration,\
    org.springframework.cloud.openfeign.FeignAutoConfiguration,\
    org.springframework.cloud.openfeign.encoding.FeignAcceptGzipEncodingAutoConfiguration,\
    org.springframework.cloud.openfeign.encoding.FeignContentGzipEncodingAutoConfiguration,\
    org.springframework.cloud.openfeign.loadbalancer.FeignLoadBalancerAutoConfiguration
    

    在FeignLoadBalancerAutoConfiguration里发现了

    @ConditionalOnClass({Feign.class})
    @ConditionalOnBean({LoadBalancerClient.class, LoadBalancerClientFactory.class})
    @AutoConfigureBefore({FeignAutoConfiguration.class})
    @AutoConfigureAfter({BlockingLoadBalancerClientAutoConfiguration.class, LoadBalancerAutoConfiguration.class})
    @EnableConfigurationProperties({FeignHttpClientProperties.class})
    @Configuration(
        proxyBeanMethods = false
    )
    @Import({HttpClientFeignLoadBalancerConfiguration.class, OkHttpFeignLoadBalancerConfiguration.class, HttpClient5FeignLoadBalancerConfiguration.class, DefaultFeignLoadBalancerConfiguration.class})
    public class FeignLoadBalancerAutoConfiguration {
        public FeignLoadBalancerAutoConfiguration() {
        }
    }
    

    一共引进了4个LoadBalancer

    // ApacheHttpClient请求配置
    HttpClientFeignLoadBalancerConfiguration.class
    // OkHttp请求配置
    OkHttpFeignLoadBalancerConfiguration.class
    // ApacheHttpClient5请求配置
    HttpClient5FeignLoadBalancerConfiguration.class
    // 默认Url请求配置
    DefaultFeignLoadBalancerConfiguration.class
    

    因为我们没做任何配置所以走DefaultFeignLoadBalancerConfiguration

    @Configuration(
        proxyBeanMethods = false
    )
    @EnableConfigurationProperties({LoadBalancerProperties.class})
    class DefaultFeignLoadBalancerConfiguration {
        DefaultFeignLoadBalancerConfiguration() {
        }
    
        @Bean
        @ConditionalOnMissingBean
        @Conditional({OnRetryNotEnabledCondition.class})
        public Client feignClient(LoadBalancerClient loadBalancerClient, LoadBalancerProperties properties, LoadBalancerClientFactory loadBalancerClientFactory) {
            return new FeignBlockingLoadBalancerClient(new Default((SSLSocketFactory)null, (HostnameVerifier)null), loadBalancerClient, properties, loadBalancerClientFactory);
        }
    
        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnClass(
            name = {"org.springframework.retry.support.RetryTemplate"}
        )
        @ConditionalOnBean({LoadBalancedRetryFactory.class})
        @ConditionalOnProperty(
            value = {"spring.cloud.loadbalancer.retry.enabled"},
            havingValue = "true",
            matchIfMissing = true
        )
        public Client feignRetryClient(LoadBalancerClient loadBalancerClient, LoadBalancedRetryFactory loadBalancedRetryFactory, LoadBalancerProperties properties, LoadBalancerClientFactory loadBalancerClientFactory) {
            return new RetryableFeignBlockingLoadBalancerClient(new Default((SSLSocketFactory)null, (HostnameVerifier)null), loadBalancerClient, loadBalancedRetryFactory, properties, loadBalancerClientFactory);
        }
    }
    

    spring.cloud.loadbalancer.retry.enabled 这个我们没配
    所以Client就是RetryableFeignBlockingLoadBalancerClient

    再看Targeter
    不罗嗦了,是在FeignAutoConfiguration里配的
    这里同时还生产了很多类
    其中FeignContext很重要,之后讲

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(Feign.class)
    @EnableConfigurationProperties({ FeignClientProperties.class, FeignHttpClientProperties.class,
            FeignEncoderProperties.class })
    @Import(DefaultGzipDecoderConfiguration.class)
    public class FeignAutoConfiguration {
    
            @Bean
        public FeignContext feignContext() {
            FeignContext context = new FeignContext();
            context.setConfigurations(this.configurations);
            return context;
        }
    
        @Configuration(proxyBeanMethods = false)
        @Conditional(FeignCircuitBreakerDisabledConditions.class)
        protected static class DefaultFeignTargeterConfiguration {
    
            @Bean
            @ConditionalOnMissingBean
            public Targeter feignTargeter() {
                return new DefaultTargeter();
            }
    
        }
    }
    

    没有feign.circuitbreaker.enabled或它为false时
    返回DefaultTargeter

    class DefaultTargeter implements Targeter {
    
        @Override
        public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
                Target.HardCodedTarget<T> target) {
            return feign.target(target);
        }
    
    }
    

    然后看Builder 的target了

    public static class Builder {
            private final List<RequestInterceptor> requestInterceptors = new ArrayList();
            private Level logLevel;
            private Contract contract;
            private Client client;
            private Retryer retryer;
            private Logger logger;
            private Encoder encoder;
            private Decoder decoder;
            private QueryMapEncoder queryMapEncoder;
            private ErrorDecoder errorDecoder;
            private Options options;
            private InvocationHandlerFactory invocationHandlerFactory;
            private boolean decode404;
            private boolean closeAfterDecode;
            private ExceptionPropagationPolicy propagationPolicy;
            private boolean forceDecoding;
            private List<Capability> capabilities;
    
            public Builder() {
                this.logLevel = Level.NONE;
                this.contract = new Default();
                this.client = new feign.Client.Default((SSLSocketFactory)null, (HostnameVerifier)null);
                this.retryer = new feign.Retryer.Default();
                this.logger = new NoOpLogger();
                this.encoder = new feign.codec.Encoder.Default();
                this.decoder = new feign.codec.Decoder.Default();
                this.queryMapEncoder = new FieldQueryMapEncoder();
                this.errorDecoder = new feign.codec.ErrorDecoder.Default();
                this.options = new Options();
                this.invocationHandlerFactory = new feign.InvocationHandlerFactory.Default();
                this.closeAfterDecode = true;
                this.propagationPolicy = ExceptionPropagationPolicy.NONE;
                this.forceDecoding = false;
                this.capabilities = new ArrayList();
            }
    
            。。。
    
            public <T> T target(Target<T> target) {
                return build().newInstance(target);
            }
            public Feign build() {
                Client client = (Client)Capability.enrich(this.client, this.capabilities);
                Retryer retryer = (Retryer)Capability.enrich(this.retryer, this.capabilities);
                List<RequestInterceptor> requestInterceptors = (List)this.requestInterceptors.stream().map((ri) -> {
                    return (RequestInterceptor)Capability.enrich(ri, this.capabilities);
                }).collect(Collectors.toList());
                Logger logger = (Logger)Capability.enrich(this.logger, this.capabilities);
                Contract contract = (Contract)Capability.enrich(this.contract, this.capabilities);
                Options options = (Options)Capability.enrich(this.options, this.capabilities);
                Encoder encoder = (Encoder)Capability.enrich(this.encoder, this.capabilities);
                Decoder decoder = (Decoder)Capability.enrich(this.decoder, this.capabilities);
                InvocationHandlerFactory invocationHandlerFactory = (InvocationHandlerFactory)Capability.enrich(this.invocationHandlerFactory, this.capabilities);
                QueryMapEncoder queryMapEncoder = (QueryMapEncoder)Capability.enrich(this.queryMapEncoder, this.capabilities);
                Factory synchronousMethodHandlerFactory = new Factory(client, retryer, requestInterceptors, logger, this.logLevel, this.decode404, this.closeAfterDecode, this.propagationPolicy, this.forceDecoding);
                ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder, this.errorDecoder, synchronousMethodHandlerFactory);
                return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
            }
        }
    

    来了
    ReflectiveFeign.newInstance
    返回代理类

    public class ReflectiveFeign extends Feign {
    
      private final ParseHandlersByName targetToHandlersByName;
      private final InvocationHandlerFactory factory;
      private final QueryMapEncoder queryMapEncoder;
    
      ReflectiveFeign(ParseHandlersByName targetToHandlersByName, InvocationHandlerFactory factory,
          QueryMapEncoder queryMapEncoder) {
        this.targetToHandlersByName = targetToHandlersByName;
        this.factory = factory;
        this.queryMapEncoder = queryMapEncoder;
      }
    
      /**
       * creates an api binding to the {@code target}. As this invokes reflection, care should be taken
       * to cache the result.
       */
      @SuppressWarnings("unchecked")
      @Override
      public <T> T newInstance(Target<T> target) {
        Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
        Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
        List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
    
        for (Method method : target.type().getMethods()) {
          if (method.getDeclaringClass() == Object.class) {
            continue;
          } else if (Util.isDefault(method)) {
            DefaultMethodHandler handler = new DefaultMethodHandler(method);
            defaultMethodHandlers.add(handler);
            methodToHandler.put(method, handler);
          } else {
            methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
          }
        }
        InvocationHandler handler = factory.create(target, methodToHandler);
        T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
            new Class<?>[] {target.type()}, handler);
    
        for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
          defaultMethodHandler.bindTo(proxy);
        }
        return proxy;
      }
    }
    

    到此为止, Open Feign 的加载过程讲完了
    但 还不够详细下面在补充点

    FeignContext

    之前提到了FeignContext
    任何一段程序都是运行在一个上下文环境中的
    所以看看它做了些什么

    public class FeignAutoConfiguration {
    
        @Autowired(required = false)
        private List<FeignClientSpecification> configurations = new ArrayList<>();
    
        @Bean
        public FeignContext feignContext() {
            FeignContext context = new FeignContext();
            context.setConfigurations(this.configurations);
            return context;
        }
    }
    

    FeignContext是在FeignAutoConfiguration 里生产出来的
    并传入了configurations:所有由@FeignClient注解的类

    FeignContext
    继承自:NamedContextFactory
    构造函数里,给父类构造函数传了个FeignClientsConfiguration.class
    真正的配置都在FeignClientsConfiguration里

    public class FeignContext extends NamedContextFactory<FeignClientSpecification> {
    
        public FeignContext() {
            super(FeignClientsConfiguration.class, "feign", "feign.client.name");
        }
    
            // 下面两个函数 取得Bean用的
        @Nullable
        public <T> T getInstanceWithoutAncestors(String name, Class<T> type) {。。。}
    
        @Nullable
        public <T> Map<String, T> getInstancesWithoutAncestors(String name, Class<T> type) {。。。 }
    
    }
    

    NamedContextFactory

    构造函数并没有做什么
    大家可以向上找,找到Client 的创建过程
    里面的函数getContext
    其中用到了
    createContext:初始化 每个@FeignClient 的context

    public abstract class NamedContextFactory<C extends NamedContextFactory.Specification>
            implements DisposableBean, ApplicationContextAware {
          public NamedContextFactory(Class<?> defaultConfigType, String propertySourceName, String propertyName) {
            this.defaultConfigType = defaultConfigType;
            this.propertySourceName = propertySourceName;
            this.propertyName = propertyName;
        }
    
        protected AnnotationConfigApplicationContext createContext(String name) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    
                    // 这块是 取得 @EnableFeignClients @FeignClient 注解里的configuration 并将他们注册到对应的 context里
            if (this.configurations.containsKey(name)) {
                for (Class<?> configuration : this.configurations.get(name).getConfiguration()) {
                    context.register(configuration);
                }
            }
            for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
                if (entry.getKey().startsWith("default.")) {
                    for (Class<?> configuration : entry.getValue().getConfiguration()) {
                        context.register(configuration);
                    }
                }
            }
            context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType);
            context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(this.propertySourceName,
                    Collections.<String, Object>singletonMap(this.propertyName, name)));
            if (this.parent != null) {
                // Uses Environment from parent as well as beans
                context.setParent(this.parent);
                // jdk11 issue
                // https://github.com/spring-cloud/spring-cloud-netflix/issues/3101
                context.setClassLoader(this.parent.getClassLoader());
            }
            context.setDisplayName(generateDisplayName(name));
            context.refresh();
            return context;
        }
    
    }
    

    这句话注册了FeignClientsConfiguration
    也就是说它会被spring容器管理并加载

    context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType);
    

    好看看它都做了什么
    FeignClientsConfiguration

    @Configuration(proxyBeanMethods = false)
    public class FeignClientsConfiguration {
    
        。。。
    
        @Bean
        @ConditionalOnMissingBean
        public Decoder feignDecoder() {。。。  }
    
        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnMissingClass("org.springframework.data.domain.Pageable")
        public Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) {
            。。。
        }
    
        @Bean
        @ConditionalOnClass(name = "org.springframework.data.domain.Pageable")
        @ConditionalOnMissingBean
        public Encoder feignEncoderPageable(ObjectProvider<AbstractFormWriter> formWriterProvider) {
            。。。
        }
    
        @Bean
        @ConditionalOnClass(name = "org.springframework.data.domain.Pageable")
        @ConditionalOnMissingBean
        public QueryMapEncoder feignQueryMapEncoderPageable() {
            。。。
        }
    
        @Bean
        @ConditionalOnMissingBean
        public Contract feignContract(ConversionService feignConversionService) {
            boolean decodeSlash = feignClientProperties == null || feignClientProperties.isDecodeSlash();
            return new SpringMvcContract(this.parameterProcessors, feignConversionService, decodeSlash);
        }
    
        @Bean
        public FormattingConversionService feignConversionService() {
            FormattingConversionService conversionService = new DefaultFormattingConversionService();
            for (FeignFormatterRegistrar feignFormatterRegistrar : this.feignFormatterRegistrars) {
                feignFormatterRegistrar.registerFormatters(conversionService);
            }
            return conversionService;
        }
    
        。。。
    
    }
    

    encode,decode什么的不说了
    主要是feignContract方法
    创建了SpringMvcContract
    Feign本身是由一套自己的注解的,但用了OpenFeign就可以直接使用springmvc的注解了
    就是由这个类完成了转换

    SpringMvcContract
    继承自:Contract.BaseContract
    实现了:ResourceLoaderAware
    具体的实现我就不讲了,看下我列出来的两个方法

    public class SpringMvcContract extends Contract.BaseContract implements ResourceLoaderAware {
        public SpringMvcContract(List<AnnotatedParameterProcessor> annotatedParameterProcessors,
                ConversionService conversionService, boolean decodeSlash) {
            Assert.notNull(annotatedParameterProcessors, "Parameter processors can not be null.");
            Assert.notNull(conversionService, "ConversionService can not be null.");
    
            List<AnnotatedParameterProcessor> processors = getDefaultAnnotatedArgumentsProcessors();
            processors.addAll(annotatedParameterProcessors);
    
            annotatedArgumentProcessors = toAnnotatedArgumentProcessorMap(processors);
            this.conversionService = conversionService;
            convertingExpanderFactory = new ConvertingExpanderFactory(conversionService);
            this.decodeSlash = decodeSlash;
        }
    
        private List<AnnotatedParameterProcessor> getDefaultAnnotatedArgumentsProcessors() {
    
            List<AnnotatedParameterProcessor> annotatedArgumentResolvers = new ArrayList<>();
                    // 这些注解的名字大家都应该熟悉吧
            annotatedArgumentResolvers.add(new MatrixVariableParameterProcessor());
            annotatedArgumentResolvers.add(new PathVariableParameterProcessor());
            annotatedArgumentResolvers.add(new RequestParamParameterProcessor());
            annotatedArgumentResolvers.add(new RequestHeaderParameterProcessor());
            annotatedArgumentResolvers.add(new QueryMapParameterProcessor());
            annotatedArgumentResolvers.add(new RequestPartParameterProcessor());
    
            return annotatedArgumentResolvers;
        }
            。。。
    }
    

    open feign 从3.0开始就不支持Ribbon

    相关文章

      网友评论

          本文标题:spring boot Open Feign 客户端加载过程

          本文链接:https://www.haomeiwen.com/subject/ooxvcltx.html