zoukankan      html  css  js  c++  java
  • SpringCloud之Feign注解@EnableFeignClients

    一  @EnableFeignClients

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Documented
    @Import(FeignClientsRegistrar.class)
    public @interface EnableFeignClients {

      在解析配置类的时候就会把@Import的内容解析出来并执行里面的方法

      

    class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
            ResourceLoaderAware, EnvironmentAware {
    
        // patterned after Spring Integration IntegrationComponentScanRegistrar
        // and RibbonClientsConfigurationRegistgrar
    
        private ResourceLoader resourceLoader;
    
        private Environment environment;
    
        public FeignClientsRegistrar() {
        }
    
        @Override
        public void setResourceLoader(ResourceLoader resourceLoader) {
            this.resourceLoader = resourceLoader;
        }
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata metadata,
                BeanDefinitionRegistry registry) {
            registerDefaultConfiguration(metadata, registry);
            registerFeignClients(metadata, registry);
        }
    public void registerFeignClients(AnnotationMetadata metadata,
                BeanDefinitionRegistry registry) {
            ClassPathScanningCandidateComponentProvider scanner = getScanner();
            scanner.setResourceLoader(this.resourceLoader);
    
            Set<String> basePackages;
    
            Map<String, Object> attrs = metadata
                    .getAnnotationAttributes(EnableFeignClients.class.getName());
            AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
                    FeignClient.class);
            final Class<?>[] clients = attrs == null ? null
                    : (Class<?>[]) attrs.get("clients");
            if (clients == null || clients.length == 0) {
                scanner.addIncludeFilter(annotationTypeFilter);
                basePackages = getBasePackages(metadata);
            }
            else {
                final Set<String> clientClasses = new HashSet<>();
                basePackages = new HashSet<>();
                for (Class<?> clazz : clients) {
                    basePackages.add(ClassUtils.getPackageName(clazz));
                    clientClasses.add(clazz.getCanonicalName());
                }
                AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
                    @Override
                    protected boolean match(ClassMetadata metadata) {
                        String cleaned = metadata.getClassName().replaceAll("\$", ".");
                        return clientClasses.contains(cleaned);
                    }
                };
                scanner.addIncludeFilter(
                        new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
            }
    
            for (String basePackage : basePackages) {
                Set<BeanDefinition> candidateComponents = scanner
                        .findCandidateComponents(basePackage);
                for (BeanDefinition candidateComponent : candidateComponents) {
                    if (candidateComponent instanceof AnnotatedBeanDefinition) {
                        // verify annotated class is an interface
                        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 = getClientName(attributes);
                        registerClientConfiguration(registry, name,
                                attributes.get("configuration"));
    
                        registerFeignClient(registry, annotationMetadata, attributes);
                    }
                }
            }
        }

    上面的代码就会把用注解FeignClient装饰的接口扫描出来并构建成一个BeanDefinition

    private void registerFeignClient(BeanDefinitionRegistry registry,
                AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
            String className = annotationMetadata.getClassName();
            BeanDefinitionBuilder definition = BeanDefinitionBuilder
                    .genericBeanDefinition(FeignClientFactoryBean.class);
            validate(attributes);
            definition.addPropertyValue("url", getUrl(attributes));
            definition.addPropertyValue("path", getPath(attributes));
            String name = getName(attributes);
            definition.addPropertyValue("name", name);
            definition.addPropertyValue("type", className);
            definition.addPropertyValue("decode404", attributes.get("decode404"));
            definition.addPropertyValue("fallback", attributes.get("fallback"));
            definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
            definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
    
            String alias = name + "FeignClient";
            AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
    
            boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null
    
            beanDefinition.setPrimary(primary);
    
            String qualifier = getQualifier(attributes);
            if (StringUtils.hasText(qualifier)) {
                alias = qualifier;
            }
    
            BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
                    new String[] { alias });
            BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
        }

      FeignClientFactoryBean注意这个FactoryBean,很关键

    public Object getObject() throws Exception {
            FeignContext context = applicationContext.getBean(FeignContext.class);
            Feign.Builder builder = feign(context);
    
            if (!StringUtils.hasText(this.url)) {//url是""所以这里走到这个分支
                String url;
                if (!this.name.startsWith("http")) {
                    url = "http://" + this.name;
                }
                else {
                    url = this.name;
                }
                url += cleanPath();//url最后的值是http://service-hi
                return loadBalance(builder, context, new HardCodedTarget<>(this.type,//type是接口类下面有截图
                        this.name, url));
            }
            if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
                this.url = "http://" + this.url;
            }
            String url = this.url + cleanPath();
            Client client = getOptional(context, Client.class);
            if (client != null) {
                if (client instanceof LoadBalancerFeignClient) {
                    // not lod balancing because we have a url,
                    // but ribbon is on the classpath, so unwrap
                    client = ((LoadBalancerFeignClient)client).getDelegate();
                }
                builder.client(client);
            }
            Targeter targeter = get(context, Targeter.class);
            return targeter.target(this, builder, context, new HardCodedTarget<>(
                    this.type, this.name, url));
        }

      

    @FeignClient(value = "service-hi")
    public interface SchedualServiceHi 
    protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
                HardCodedTarget<T> target) {
            Client client = getOptional(context, Client.class);
            if (client != null) {
                builder.client(client);
                Targeter targeter = get(context, Targeter.class);
                return targeter.target(this, builder, context, target);
            }

    如果没有和Hystrix等结合那么client就是 LoadBalancerFeignClient

    最终还是对调用targeter.target生成代理,因为要处理和Hystrix等相结合的情况

  • 相关阅读:
    洛谷 P2058 海港(模拟)
    LA 3708 墓地雕塑(模拟)
    Uva 11300 Spreading the Wealth(贪心)
    UVA 11729 Commando War (贪心)
    【洛谷习题】Likecloud-吃、吃、吃
    【洛谷习题】多米诺骨牌
    【洛谷习题】相似基因
    【NOI1995】石子合并
    【洛谷习题】尼克的任务
    【NOIP2004】合唱队形
  • 原文地址:https://www.cnblogs.com/juniorMa/p/14427514.html
Copyright © 2011-2022 走看看