Registration process and source code of SpringCloudFeign

Microservices can be accessed using restTemplate or feign for remote calls. Feign uses ribbon by default to achieve load balancing. A declarative
pseudo-Http client that integrates feign and Hystrix, and combines big and eureka to achieve load balancing and circuit breakers.
When FeignAutoConfiguration is automatically assembled, a Targeter configuration bean is created, and HystrixTargeter is used by default to implement a circuit breaker
insert image description here

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
//启动类注解引入了一个注册类
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients 


//注册类
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    
    

//feign启动时会将需要扫描的配置
//我们定义的feign接口动态代理对象的创建
@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
    
    
		//解析全局配置,如@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class) 
		//feign针对不同的服务调用可设置自定义的配置,如在启动类上设置,即为全局配置,即所有的feign调用都会引入此配置
		registerDefaultConfiguration(metadata, registry);
		//解析我们定义的feign接口,解析局部配置,创建代理对象
		registerFeignClients(metadata, registry);
	}

//================================先说第一个方法===============================

 /**
     * @Description: 解析全局配置并注册到beanDefinitionMap中
     * @Author: PABLO
     * @Date: 2022/5/20 12:44
     * @Params: [metadata 启动类, registry注册器]
     * @Return: void
     **/
    private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
    
    
        //通过启动类注解获取该注解中定义的信息,如下
        /*
        String[] value() default {};
        String[] basePackages() default {};
        Class<?>[] basePackageClasses() default {};
        Class<?>[] defaultConfiguration() default {};
        Class<?>[] clients() default {};
        */
        Map<String, Object> defaultAttrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
        //如果配置了defaultConfiguration  即全局的feign配置
        if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
    
    
            String name;
            //前缀
            if (metadata.hasEnclosingClass()) {
    
    
                name = "default." + metadata.getEnclosingClassName();
            } else {
    
    
                name = "default." + metadata.getClassName();
            }
            //注册
            registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration"));
        }
    }
    /**
     * @Description:注册feign的全局配置信息到beanDefinitionMap中
     * @Author: PABLO
     * @Date: 2022/5/20 12:49
     * @Params: [registry 注册器, name 加了前缀的名称,如default.com.gator.feign.Application, configuration配置信息]
     * @Return: void
     **/
    private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
    
    
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
        builder.addConstructorArgValue(name);
        builder.addConstructorArgValue(configuration);
        registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),
                builder.getBeanDefinition());
    }


}

//================================第二个方法(重点)===============================

  /**
     * @Description: 将feign接口的自定义配置添加到beanDefinitionMap&创建该接口的代理对象(特殊bean-->FactoryBean)
     * @Author: PABLO
     * @Date: 2022/5/20 12:58
     * @Params: [metadata 注解修饰的元数据 , registry 注册器]
     * @Return: void
     **/
    public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
    
    

        LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();
        //获取启动类注解中所有定义的信息
        Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
        //获取启动类上的client列表中是否配置了对应feign接口即@FeignClient
        //注意:如果client[]不为null,禁用类路径扫描
        final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");
        //扫描basePackage下的所有@FeignClient修饰的class
        if (clients == null || clients.length == 0) {
    
    
            ClassPathScanningCandidateComponentProvider scanner = getScanner();
            //资源加载器
            scanner.setResourceLoader(this.resourceLoader);
            //筛选出符合要求的class
            scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));
            //获取basePackage,启动类所在的包
            Set<String> basePackages = getBasePackages(metadata);
            //扫描类路径寻找符合要求的组件,即class
            for (String basePackage : basePackages) {
    
    
                candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
            }
        } else {
    
    
            //启动类上指定了feign接口的class,注解添加
            for (Class<?> clazz : clients) {
    
    
                candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz));
            }
        }
        for (BeanDefinition candidateComponent : candidateComponents) {
    
    
            if (candidateComponent instanceof AnnotatedBeanDefinition) {
    
    
                // 判断这些@FeignClient修饰的class是否为接口(后续需要借口代理,必须是接口)
                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());
                //获取注解中配置的远程节点的信息如 eureka-client
                String name = getClientName(attributes);
                //获取注解中配置的自定义配置类信息并注册到beanDefinitionMap中
                registerClientConfiguration(registry, name, attributes.get("configuration"));
                //针对@FeignClient修饰的接口的操作
                registerFeignClient(registry, annotationMetadata, attributes);
            }
        }
    }

    /**
     * @Description:
     * @Author: PABLO
     * @Date: 2022/5/20 13:11
     * @Params: [registry 注册器, annotationMetadata @FeignClient修饰的接口, attributes @FeignClient中的定义信息]
     * @Return: void
     **/
    private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata,
                                     Map<String, Object> attributes) {
    
    
        //类名
        String className = annotationMetadata.getClassName();
        Class clazz = ClassUtils.resolveClassName(className, null);
        ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory
                ? (ConfigurableBeanFactory) registry : null;
        //get
        String contextId = getContextId(beanFactory, attributes);
        String name = getName(attributes);
        //这是特殊处理的bean,和mybatis中的MapperFactoryBean一样
        FeignClientFactoryBean factoryBean = new FeignClientFactoryBean();
        factoryBean.setBeanFactory(beanFactory);
        factoryBean.setName(name);
        factoryBean.setContextId(contextId);
        factoryBean.setType(clazz);
        factoryBean.setRefreshableClient(isClientRefreshEnabled());
        BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> {
    
    
            //完善属性
            factoryBean.setUrl(getUrl(beanFactory, attributes));
            factoryBean.setPath(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(), null));
            }
            Object fallbackFactory = attributes.get("fallbackFactory");
            if (fallbackFactory != null) {
    
    
                factoryBean.setFallbackFactory(fallbackFactory instanceof Class ? (Class<?>) fallbackFactory
                        : ClassUtils.resolveClassName(fallbackFactory.toString(), null));
            }
            //这里是factoryBean的核心方法,后面我列出了调用链路
            return factoryBean.getObject();
        });
        //set
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        definition.setLazyInit(true);
        validate(attributes);
        //构建beanDefinition
        AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
        beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
        beanDefinition.setAttribute("feignClientsRegistrarFactoryBean", factoryBean);

        //标记feign接口对应的代理对象是否为主要bean
        boolean primary = (Boolean) attributes.get("primary");
        beanDefinition.setPrimary(primary);
        //修饰词 如 eureka-clientFeignClient
        String[] qualifiers = getQualifiers(attributes);
        if (ObjectUtils.isEmpty(qualifiers)) {
    
    
            qualifiers = new String[]{
    
    contextId + "FeignClient"};
        }
        //构建描述持有者对象
        BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
        //注册
        BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
        //这个是针对动态刷新的,感兴趣的宝子们可以自己瞅瞅
        registerOptionsBeanDefinition(registry, contextId);
    }


    //-----------------------------------------创建代理对象链路-----------------------------------------
    public Object getObject() {
    
    
        return getTarget();
    }

    <T> T getTarget() {
    
    
        //......
        return (T) loadBalance(builder, context, new Target.HardCodedTarget<>(type, name, url));
        //.......

        //.......

    }

    protected <T> T loadBalance(Feign.Builder builder, FeignContext context, Target.HardCodedTarget<T> target) {
    
    
        //......
        return targeter.target(this, builder, context, target);
    }

    public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
                        Target.HardCodedTarget<T> target) {
    
    
                        //.....断路器.....
        return feign.target(target);
    }

    public <T> T target(Target<T> target) {
    
    
        return build().newInstance(target);
    }

    public <T> T newInstance(Target<T> target) {
    
    
        //.......
        T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
                new Class<?>[]{
    
    target.type()}, handler);
        //.......
        return proxy;
    }



//生成的代理类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.sun.proxy;

import com.gator.feign.client.EurekaClientFeign;
import com.gator.feign.domain.Parent;
import com.gator.feign.domain.Student;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy76 extends Proxy implements RemoteFeign {
    
    
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m4;
    private static Method m0;
    private static Method m5;

    public $Proxy76(InvocationHandler var1) throws  {
    
    
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
    
    
        try {
    
    
            return (Boolean)super.h.invoke(this, m1, new Object[]{
    
    var1});
        } catch (RuntimeException | Error var3) {
    
    
            throw var3;
        } catch (Throwable var4) {
    
    
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
    
    
        try {
    
    
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
    
    
            throw var2;
        } catch (Throwable var3) {
    
    
            throw new UndeclaredThrowableException(var3);
        }
    }
	//我的方法
    public final Student postGetInfo(Parent var1) throws  {
    
    
        try {
    
    
            return (Student)super.h.invoke(this, m3, new Object[]{
    
    var1});
        } catch (RuntimeException | Error var3) {
    
    
            throw var3;
        } catch (Throwable var4) {
    
    
            throw new UndeclaredThrowableException(var4);
        }
    }
	//我的方法
    public final Student getInfoByFeign(String var1, String var2) throws  {
    
    
        try {
    
    
        //这里调用父类的h,即Proxy中的protected InvocationHandler h;
        //最终会调用invoke
            return (Student)super.h.invoke(this, m4, new Object[]{
    
    var1, var2});
        } catch (RuntimeException | Error var4) {
    
    
            throw var4;
        } catch (Throwable var5) {
    
    
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final int hashCode() throws  {
    
    
        try {
    
    
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
    
    
            throw var2;
        } catch (Throwable var3) {
    
    
            throw new UndeclaredThrowableException(var3);
        }
    }
	//我的方法
    public final String getInfo() throws  {
    
    
        try {
    
    
            return (String)super.h.invoke(this, m5, (Object[])null);
        } catch (RuntimeException | Error var2) {
    
    
            throw var2;
        } catch (Throwable var3) {
    
    
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
    
    
        try {
    
    
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.gator.feign.client.EurekaClientFeign").getMethod("postStudentByFeign", Class.forName("com.gator.feign.domain.Parent"));
            m4 = Class.forName("com.gator.feign.client.EurekaClientFeign").getMethod("getStudentByFeign", Class.forName("java.lang.String"), Class.forName("java.lang.String"));
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m5 = Class.forName("com.gator.feign.client.EurekaClientFeign").getMethod("infoByFeign");
        } catch (NoSuchMethodException var2) {
    
    
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
    
    
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}


Guess you like

Origin blog.csdn.net/GiantCrocodile/article/details/124881212