Spring-Cloud-Feign源码阅读(1)-FeignClient是如何初始化的

一、BeanDefinition和DefaultListableBeanFactory的关联

        BeanDefinition是对一个bean的描述,包括bean的各种信息,比如bean的类型、bean的属性、scope是单例还是原型、是否懒加载、init方法、destory方法等。博主这样理解,用@Bean注解定义一个bean时,bean的各种属性通常都是常量,BeanDefinition类的作用就是可以动态的去定义bean。

        DefaultListableBeanFactory类是Spring的核心类,有获取bean的各种方法。该类BeanDefinition的关联就是维护一个ConcurrentHashMap,key为beanName,value为BeanDefinition。该类中registerBeanDefinition的方法就是往ConcurrentHashMap里put一个值,这个过程称为bean的注册。该类的职责就是对所有bean的管理以及实例化。

二、FeignClient的注册器-FeignClientsRegistrar

        在Spring Boot应用中要启用Feign,要在SpringBootApplication类上面加上@EnableFeignClients注解。查看@EnableFeignClients注解源码,相比其他的普通注解多了一行@Import({FeignClientsRegistrar.class})。FeignClientsRegistrar类的对象也会被Spring容器管理。

package org.springframework.cloud.openfeign;

@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类实现了ImportBeanDefinitionRegistrar接口,所以registerBeanDefinitions方法在应用启动时就执行。

package org.springframework.cloud.openfeign;

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    private ResourceLoader resourceLoader;
    private Environment environment;

    ...

    //应用启动时执行
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        this.registerDefaultConfiguration(metadata, registry);
        this.registerFeignClients(metadata, registry);
    }

    
    //将@EnableFeignClients注解里的defaultConfiguration配置
    private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        Map defaultAttrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
        //如果EnableFeignClients.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"));
        }

    }

    //注册FeignClient
    public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        //获取扫描器
        ClassPathScanningCandidateComponentProvider scanner = this.getScanner();
        scanner.setResourceLoader(this.resourceLoader);
        //获取@EnableFeignClients注解上的配置
        Map attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
        AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
        Class[] clients = attrs == null ? null : (Class[])((Class[])attrs.get("clients"));
        Object basePackages;
        if (clients != null && clients.length != 0) {
            //如果@EnableFeignClients注解上的配置指定了clients
            final Set clientClasses = new HashSet();
            basePackages = new HashSet();
            Class[] var9 = clients;
            int var10 = clients.length;

            for(int var11 = 0; var11 < var10; ++var11) {
                Class clazz = var9[var11];
                //所有指定的clients的包路径都需要扫描
                ((Set)basePackages).add(ClassUtils.getPackageName(clazz));
                clientClasses.add(clazz.getCanonicalName());
            }

            AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
                protected boolean match(ClassMetadata metadata) {
                    String cleaned = metadata.getClassName().replaceAll("\\$", ".");
                    return clientClasses.contains(cleaned);
                }
            };
            scanner.addIncludeFilter(new FeignClientsRegistrar.AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
        } else {
            //如果@EnableFeignClients注解上的配置未指定clients,则扫描SpringBootApplication类的包以及子路径,并且是加了@FeignClient注解的类
            scanner.addIncludeFilter(annotationTypeFilter);
            basePackages = this.getBasePackages(metadata);
        }

        Iterator var17 = ((Set)basePackages).iterator();

        while(var17.hasNext()) {
            String basePackage = (String)var17.next();
            Set candidateComponents = scanner.findCandidateComponents(basePackage);
            Iterator var21 = candidateComponents.iterator();

            while(var21.hasNext()) {
                BeanDefinition candidateComponent = (BeanDefinition)var21.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");
                    //获取扫描到的类@FeignClient注解的配置
                    Map attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
                    String name = this.getClientName(attributes);
                    //注册单个FeignClient的配置 
                    this.registerClientConfiguration(registry, name, attributes.get("configuration"));
                    //注册单个@FeignClient类的定义
                    this.registerFeignClient(registry, annotationMetadata, attributes);
                }
            }
        }

    }

    private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map attributes) {
        String className = annotationMetadata.getClassName();
        //所有FeignClient的bean的类型指为FeignClientFactoryBean类型
        BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
        this.validate(attributes);
        //设置FeignClient的各种属性
        //获取@FeignClient配置的url  用于非微服务的请求url
        definition.addPropertyValue("url", this.getUrl(attributes));
        definition.addPropertyValue("path", this.getPath(attributes));
        //获取@FeignClient配置的name  微服务服务名的转发
        String name = this.getName(attributes);
        definition.addPropertyValue("name", name);
        String contextId = this.getContextId(attributes);
        definition.addPropertyValue("contextId", contextId);
        definition.addPropertyValue("type", className);
        //获取@FeignClient配置的name 用于请求状态码返回404情况下对response的编码转换
        definition.addPropertyValue("decode404", attributes.get("decode404"));
        //获取@FeignClient配置的fallback 用于指定改FeignClient的熔断类
        definition.addPropertyValue("fallback", attributes.get("fallback"));
        definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
        definition.setAutowireMode(2);
        String alias = contextId + "FeignClient";
        AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
        boolean primary = (Boolean)attributes.get("primary");
        beanDefinition.setPrimary(primary);
        String qualifier = this.getQualifier(attributes);
        if (StringUtils.hasText(qualifier)) {
            alias = qualifier;
        }

        //注册FeignClient,将FeignClient的bean以及beanDefinition注册至DefaultListableBeanFactory,在实例化bean时如果bean的类型是FactoryBean则会继续调用FactoryBean的getObject方法生成bean
        BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[]{alias});
        BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
    }

    //完成FeignClientSpecification bean的注册,该bean的类型是FeignClientSpecification是一个普通类型,则在bean实例化的时候,就会调用该类的构造方法生成实例
    private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
        //注册FeignClientSpecification bean
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
        //添加构造参数
        builder.addConstructorArgValue(name);
        builder.addConstructorArgValue(configuration);
        registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(), builder.getBeanDefinition());
    }

    ...

}

        FeignClientsRegistrar类的主要职责是

        (1)获取FeignClient bean并为其指定生成对象的类FeignClientFactoryBean,同时设置一些请求地址、服务名、以及相关配置。

        (2)将@EnableFeignClients默认的Fegin配置以及@FeignClient的配置都以bean的方式初始化成FeignClientSpecification。

三、FeignClient的配置-FeignContext

        FeignContext是一个Bean,只将FeignClientSpecification类型的所有bean注入为属性。

package org.springframework.cloud.openfeign;

@Configuration
@ConditionalOnClass({Feign.class})
@EnableConfigurationProperties({FeignClientProperties.class, FeignHttpClientProperties.class})
public class FeignAutoConfiguration {
    @Autowired(
        required = false
    )
    private List configurations = new ArrayList();

    public FeignAutoConfiguration() {
    }

    ...

    @Bean
    public FeignContext feignContext() {
        FeignContext context = new FeignContext();
        context.setConfigurations(this.configurations);
        return context;
    }
}

        FeignContext继承了NamedContextFactory类,通过这种方式把初始化的FeignClientSpecification以FeignClient的name分隔从而生成一个包含所有FeignClient配置的FeignContext bean。

package org.springframework.cloud.openfeign;

public class FeignContext extends NamedContextFactory {
    public FeignContext() {
        super(FeignClientsConfiguration.class, "feign", "feign.client.name");
    }
}
package org.springframework.cloud.context.named;


public abstract class NamedContextFactory implements DisposableBean, ApplicationContextAware {
    //通过一个name将上下文隔离
    private Map contexts = new ConcurrentHashMap();
    private Map configurations = new ConcurrentHashMap();

    ...

    public void setConfigurations(List configurations) {
        Iterator var2 = configurations.iterator();

        while(var2.hasNext()) {
            C client = (NamedContextFactory.Specification)var2.next();
            //结合FeignClientSpecification的代码,猜到FeignContext的key就是FeignClient的name
            this.configurations.put(client.getName(), client);
        }

    }

    //获取实例的时候,也先通过name获取响应的上下文
    public  T getInstance(String name, Class type) {
        AnnotationConfigApplicationContext context = this.getContext(name);
        return BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type).length > 0 ? context.getBean(type) : null;
    }

    ...

    public interface Specification {
        String getName();

        Class[] getConfiguration();
    }
}

四、FeignClient的初始化-FeignClientFactoryBean

        FeignClientFactoryBean的getObject方法生成实例。

package org.springframework.cloud.openfeign;

class FeignClientFactoryBean implements FactoryBean, InitializingBean, ApplicationContextAware {
    //相关属性都是在bean注册时,通过set方法设置值
    private Class type;
    private String name;
    private String url;
    //contextId在注册时,设置为FeignClient的name
    private String contextId;
    private String path;
    private boolean decode404;
    private ApplicationContext applicationContext;
    private Class fallback;
    private Class fallbackFactory;

    FeignClientFactoryBean() {
        this.fallback = Void.TYPE;
        this.fallbackFactory = Void.TYPE;
    }

    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.applicationContext = context;
    }

    //生成一个Builder
    protected Builder feign(FeignContext context) {
        //通过contextId和FeignContext获取FeignClient的配置
        FeignLoggerFactory loggerFactory = (FeignLoggerFactory)this.get(context, FeignLoggerFactory.class);
        Logger logger = loggerFactory.create(this.type);
        //生成FeignBuilder 主要包含的配置就是Feign的协议、日志等级配置、编码器、解码器等
        Builder builder = ((Builder)this.get(context, Builder.class)).logger(logger).encoder((Encoder)this.get(context, Encoder.class)).decoder((Decoder)this.get(context, Decoder.class)).contract((Contract)this.get(context, Contract.class));
        //获取feign.client.name相关配置并设置到builder里
        this.configureFeign(context, builder);
        return builder;
    }

    ...

    protected  T get(FeignContext context, Class type) {
        T instance = context.getInstance(this.contextId, type);
        if (instance == null) {
            throw new IllegalStateException("No bean found of type " + type + " for " + this.contextId);
        } else {
            return instance;
        }
    }

    protected  T getOptional(FeignContext context, Class type) {
        return context.getInstance(this.contextId, type);
    }

    protected  T loadBalance(Builder builder, FeignContext context, HardCodedTarget target) {
        //执行请求的Client 在FeignRibbonClientAutoConfiguration中初始化的,默认是LoadBalancerFeignClient
        Client client = (Client)this.getOptional(context, Client.class);
        if (client != null) {
            builder.client(client);
            //FeignAutoConfiguration中Targeter 初始化为HystrixTargeter
            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-netflix-ribbon?");
        }
    }

    //实例化FeignClient的方法
    public Object getObject() throws Exception {
        return this.getTarget();
    }

     T getTarget() {
        //获取FeignContext 并生成Feign.builder
        FeignContext context = (FeignContext)this.applicationContext.getBean(FeignContext.class);
        Builder builder = this.feign(context);
        //如果@FeignClient的配置url没有值,微服务中url通常都没有值,都是用的name
        if (!StringUtils.hasText(this.url)) {
            if (!this.name.startsWith("http")) {
                this.url = "http://" + this.name;
            } else {
                this.url = this.name;
            }
            this.url = this.url + this.cleanPath();
            //调用loadBalance方法生成对象,将FeignClient的type, name, url创建一个HardCodedTarget对象
            return this.loadBalance(builder, context, new HardCodedTarget(this.type, this.name, this.url));
        } else {
            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 LoadBalancerFeignClient) {
                    client = ((LoadBalancerFeignClient)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));
        }
    }

class DefaultFeignLoadBalancedConfiguration {
    DefaultFeignLoadBalancedConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean
    public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory) {
        return new LoadBalancerFeignClient(new Default((SSLSocketFactory)null, (HostnameVerifier)null), cachingFactory, clientFactory);
    }
}

public class FeignAutoConfiguration {

    ...

    @Configuration
    @ConditionalOnMissingClass({"feign.hystrix.HystrixFeign"})
    protected static class DefaultFeignTargeterConfiguration {
        protected DefaultFeignTargeterConfiguration() {
        }
        

        //如果没有HystrixFeign类,则Targeter  bean就是DefaultTargeter
        @Bean
        @ConditionalOnMissingBean
        public Targeter feignTargeter() {
            return new DefaultTargeter();
        }
    }

    ...
    @Configuration
    @ConditionalOnClass(
        name = {"feign.hystrix.HystrixFeign"}
    )
    protected static class HystrixFeignTargeterConfiguration {
        protected HystrixFeignTargeterConfiguration() {
        }

        //如果HystrixFeign类,则Targeter  bean就是HystrixTargeter
        @Bean
        @ConditionalOnMissingBean
        public Targeter feignTargeter() {
            return new HystrixTargeter();
        }
    }
}

@Configuration
public class FeignClientsConfiguration {

    @Configuration
    @ConditionalOnClass({HystrixCommand.class, HystrixFeign.class})
    protected static class HystrixFeignConfiguration {
        protected HystrixFeignConfiguration() {
        }

        //如果feign.hystrix.enabled不是true,则FeignClientFactoryBean里获取的builder就是Feign.builder 而不是HystrixFeign.Builder
        @Bean
        @Scope("prototype")
        @ConditionalOnMissingBean
        @ConditionalOnProperty(
            name = {"feign.hystrix.enabled"}
        )
        public Builder feignHystrixBuilder() {
            return HystrixFeign.builder();
        }
    }

}

         如果feign.hystrix.enabled不是true,则FeignClientFactoryBean里获取的builder就是Feign.builder 而不是HystrixFeign.Builder

class HystrixTargeter implements Targeter {
    HystrixTargeter() {
    }

    public  T target(FeignClientFactoryBean factory, Builder feign, FeignContext context, HardCodedTarget target) {
        //根据Builder的类型判断是否需要熔断
        if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
            return feign.target(target);
        } else {
            feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder)feign;
            SetterFactory setterFactory = (SetterFactory)this.getOptional(factory.getName(), context, SetterFactory.class);
            if (setterFactory != null) {
                builder.setterFactory(setterFactory);
            }

            Class fallback = factory.getFallback();
            if (fallback != Void.TYPE) {
                return this.targetWithFallback(factory.getName(), context, target, builder, fallback);
            } else {
                Class fallbackFactory = factory.getFallbackFactory();
                return fallbackFactory != Void.TYPE ? this.targetWithFallbackFactory(factory.getName(), context, target, builder, fallbackFactory) : feign.target(target);
            }
        }
    }

         以上都是获取各种配置以及根据是否开启熔断获取一个Builder。

      1.未开启熔断时, Feign.Builder

package feign;

public abstract class Feign {
    public Feign() {
    }

    ...

    public static class Builder {
       
        ...
 
        public  T target(Target target) {
            return this.build().newInstance(target);
        }

        public Feign build() {
            //new一个 InvocationHandlerFactory
            Factory synchronousMethodHandlerFactory = new Factory(this.client, this.retryer, this.requestInterceptors, this.logger, this.logLevel, this.decode404, this.closeAfterDecode, this.propagationPolicy);
            //new一个Feign解析的处理器
            ParseHandlersByName handlersByName = new ParseHandlersByName(this.contract, this.options, this.encoder, this.decoder, this.queryMapEncoder, this.errorDecoder, synchronousMethodHandlerFactory);
            //生成ReflectiveFeign对象
            return new ReflectiveFeign(handlersByName, this.invocationHandlerFactory, this.queryMapEncoder);
        }

    }
}
package feign;

public class ReflectiveFeign extends Feign {
    private final ReflectiveFeign.ParseHandlersByName targetToHandlersByName;
    private final InvocationHandlerFactory factory;
    private final QueryMapEncoder queryMapEncoder;

    ReflectiveFeign(ReflectiveFeign.ParseHandlersByName targetToHandlersByName, InvocationHandlerFactory factory, QueryMapEncoder queryMapEncoder) {
        this.targetToHandlersByName = targetToHandlersByName;
        this.factory = factory;
        this.queryMapEncoder = queryMapEncoder;
    }

    public  T newInstance(Target target) {
        //通过HardCodedTarget里的type以及Contract里的协议解析成key为MethodHandler的configKey 由类型+方法名+参数类型组成  value为MethodHandler
        Map nameToHandler = this.targetToHandlersByName.apply(target);
        
        //判断并过滤转换成key为Method value为MethodHandler的的类型
        Map methodToHandler = new LinkedHashMap();
        List defaultMethodHandlers = new LinkedList();
        Method[] var5 = target.type().getMethods();
        int var6 = var5.length;

        for(int var7 = 0; var7 < var6; ++var7) {
            Method method = var5[var7];
            if (method.getDeclaringClass() != Object.class) {
                if (Util.isDefault(method)) {
                    DefaultMethodHandler handler = new DefaultMethodHandler(method);
                    defaultMethodHandlers.add(handler);
                    methodToHandler.put(method, handler);
                } else {
                    methodToHandler.put(method, (MethodHandler)nameToHandler.get(Feign.configKey(target.type(), method)));
                }
            }
        }
        
        //转换成InvocationHandler target指定类型,Map根据方法分发
        InvocationHandler handler = this.factory.create(target, methodToHandler);
        //生成代理对象
        T proxy = Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, handler);
        Iterator var12 = defaultMethodHandlers.iterator();

        while(var12.hasNext()) {
            DefaultMethodHandler defaultMethodHandler = (DefaultMethodHandler)var12.next();
            defaultMethodHandler.bindTo(proxy);
        }

        return proxy;
    }

    ...
}

        2.未开启熔断时, HystrixFeign.Builder

           待补充

五、总结

FeignClient初始化过程如下:

(1)由FeignClientsRegistrar选择FeignClient,将FeignClient bean的类型通过BeanDefinition指定为FeignClientFactoryBean,并注册到DefaultListableBeanFactory由其管理。

(2)因为FeignClientFactoryBean实现了FactoryBean接口,DefaultListableBeanFactory在实例化FeignClient时,会调用FeignClientFactoryBean的getObject方法。

(3)通过FeignContext获取不同的FeignClient的配置以及是否开启熔断生成Feign.builder(HystrixFeign.Builder继承了Feign.Builder)。

(4)Feign.Builder创建调用处理器工厂InvocationHandlerFactory、语法解析ParseHandlersByName对象生成ReflectiveFeign对象。

(5)ReflectiveFeign类newInstance方法,将FeignClient的类通过contract解析成MethodHandler,再由InvocationHandlerFactory生成FeignInvocationHandler对象,再生成代理对象。

其他:

(1)可以通过BeanDefinition动态注册bean。

(2)集成NamedContextFactory可以通过指定的key隔离上下文,完成不同的bean可以获取到不同的配置。

(3)开启熔断后,FeignClientFactoryBean的builder就是HystrixFeign.Builder,实现了Feign.Builder,重写了其build方法,并且也有相应的调用处理器HystrixInvocationHandler和HystrixDelegatingContract(基于现有的Contract修改了返回类型)。

(4)feignClient的初始化对象是基于jdk的动态代理。

你可能感兴趣的:(Spring,Cloud,spring,eureka,java)