Feign源码阅读(二)FeignClient动态代理

2,503 阅读8分钟

一、前言

  通过@FeignClient修饰的接口要能够被使用,原因是注册到Spring容器中时是个动态代理。这一章主要学习Feign动态代理创建流程,并且自己实现一个类似的流程。

二、注册FeignClientFactoryBean

@EnableFeignClients

  @EnableFeignClients还是利用了Spring的Import注解+ImportBeanDefinitionRegistrar接口,注册Bean到Spring容器中。

@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

  FeignClientsRegistrar实现ImportBeanDefinitionRegistrar接口,负责扫描@FeignClient注解修饰的类,并注册为FeignClientFactoryBean。

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
		BeanDefinitionRegistry registry) {
	// 注册@EnableFeignClients的defaultConfiguration全局Feign配置(忽略,无非是转换为BeanDefination,注册到容器)
	registerDefaultConfiguration(metadata, registry);
	// 注册FeignClientFactoryBean
	registerFeignClients(metadata, registry);
}
  • registerFeignClients:扫描并注册FeignClientFactoryBean
public void registerFeignClients(AnnotationMetadata metadata,
		BeanDefinitionRegistry registry) {
	// 1. 创建scanner
	ClassPathScanningCandidateComponentProvider scanner = getScanner();
	scanner.setResourceLoader(this.resourceLoader);

	// 2. 获取要扫描的包名集合
	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");
	// 2-1. 如果不存在clients属性,取value、basePackages、basePackageClasses所在包的并集作为扫描包路径,如果并集为空,取注解所在包路径
	if (clients == null || clients.length == 0) {
		scanner.addIncludeFilter(annotationTypeFilter);
		basePackages = getBasePackages(metadata);
	}
	else {
		// 2-2. 如果存在clients属性,取clients所在包集合作为扫描路径,并且过滤出和client类名一致的类
		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) {
		// 3. 循环所有包路径,扫描出BeanDefinition
		Set<BeanDefinition> candidateComponents = scanner
				.findCandidateComponents(basePackage);
		for (BeanDefinition candidateComponent : candidateComponents) {
			AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
			AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();

			Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
			// 获取特殊配置注册到全局容器的beanName前缀
			String name = getClientName(attributes);
			// 4. 注册特殊配置到全局Spring容器
			registerClientConfiguration(registry, name,attributes.get("configuration"));
			// 5. 注册FeignClientFactoryBean到全局Spring容器
			registerFeignClient(registry, annotationMetadata, attributes);
		}
	}
}
  • getClientName获取特殊配置的beanName前缀

  优先级contextId>value>name>serviceId

private String getClientName(Map<String, Object> client) {
	if (client == null) {
		return null;
	}
	String value = (String) client.get("contextId");
	if (!StringUtils.hasText(value)) {
		value = (String) client.get("value");
	}
	if (!StringUtils.hasText(value)) {
		value = (String) client.get("name");
	}
	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());
}
  • registerClientConfiguration注册客户端特殊配置到全局Spring容器

  这个和RibbonClientConfigurationRegistrar的registerClientConfiguration长的差不多,关键点就是getClientName获取到的BeanName前缀。当同一个service提供多个client时,常因为这里的name一致,导致beanName冲突,容器启动报错,这个解决方案后续再说。

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());
}
  • registerFeignClient注册FeignClientFactoryBean到全局Spring容器
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));
	// 取name属性 serviceId>name>value
	String name = getName(attributes);
	definition.addPropertyValue("name", name);
	// 取contextId属性,contextId>serviceId>name>value
    // 非常重要,后续从FeignContext中获取子容器就是通过contextId
	String contextId = getContextId(attributes);
	definition.addPropertyValue("contextId", contextId);
	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 = contextId + "FeignClient";
	AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
	beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);

	// 设置Bean是否是Primary的,默认是是,如果提供二方包出去,最好设置false方便调用方覆盖
	boolean primary = (Boolean) attributes.get("primary");
	beanDefinition.setPrimary(primary);
	// 如果qualifier属性不为空,使用qualifier属性作为别名,否则使用contextId + "FeignClient"
	String qualifier = getQualifier(attributes);
	if (StringUtils.hasText(qualifier)) {
		alias = qualifier;
	}
	BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
			new String[] { alias });
	BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}

三、FeignClientFactoryBean实例化动态代理

FeignClientFactoryBean作为一个FactoryBean在Spring容器最后加载单例对象的时候不会实例化目标对象,被调用getObject方法。除非一个单例Bean的populate阶段需要注入一个FeignClient,他的getObject方法才会被调用,这也是FactoryBean和普通Bean不一样的地方。

DefaultListableBeanFactory#preInstantiateSingletons
public void preInstantiateSingletons() throws BeansException {
  List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
  for (String beanName : beanNames) {
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
          if (isFactoryBean(beanName)) {
          	  // 实例化FeignClientFactoryBean
              Object bean = getBean("&" + beanName);
              if (bean instanceof FactoryBean) {
                  final FactoryBean<?> factory = (FactoryBean<?>) bean;
                  boolean isEagerInit;
                  if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                      isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                      ((SmartFactoryBean<?>) factory)::isEagerInit,
                              getAccessControlContext());
                  } else {
                      isEagerInit = (factory instanceof SmartFactoryBean &&
                              ((SmartFactoryBean<?>) factory).isEagerInit());
                  }
                  // 如果是SmartFactoryBean且isEagerInit=true则实例化目标对象,否则不实例化目标对象
                  if (isEagerInit) {
                      getBean(beanName);
                  }
              }
          }
          ...
      }
      ...
  }
  ...
}

最外层:FeignClientFactoryBean.getTarget方法

@Override
public Object getObject() throws Exception {
	return getTarget();
}
/**
* T 就是@FeignClient修饰的接口的动态代理对象
*/
<T> T getTarget() {
	// 获取到FeignContext,相当于有了各种Decoder、Encoder等等
	FeignContext context = this.applicationContext.getBean(FeignContext.class);
	// 利用FeiContext的命名子容器和全局Spring容器(this.applicationContext)里的东西
	// 构建Feign.Builder
	Feign.Builder builder = feign(context);

	if (!StringUtils.hasText(this.url)) {
		// 处理url属性,最后是http://服务名/this.path
		if (!this.name.startsWith("http")) {
			this.url = "http://" + this.name;
		}
		else {
			this.url = this.name;
		}
		this.url += cleanPath();
		// loadBalance方法主要是通过Target.target方法获取最终的代理对象
		return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type, this.name, this.url));
	}
	// 忽略下面的代码,因为我们一般不会指定url,只要知道指定url可以直连某个ip:port的服务
}

1、feign(FeignContext)构建Feign.Builder

protected Feign.Builder feign(FeignContext context) {
   FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
   Logger logger = loggerFactory.create(this.type);
   // 通过this.contextId从子容器获取所有必须的实例
   // 如果如果引入了Hystrix相关jar包,并且feign.hystrix.enabled=true,则调用Feign.Builder=feign.hystrix.HystrixFeign.Builder,否则=feign.Feign.Builder
   Feign.Builder builder = get(context, Feign.Builder.class)
   		// required values
   		.logger(logger)
   		.encoder(get(context, Encoder.class))
   		.decoder(get(context, Decoder.class))
   		.contract(get(context, Contract.class));
   // 继续其余配置,包括超时、Retryer等配置的读取,并放入builder对象
   // 暂时忽略,等将服务特殊配置的时候再看
   configureFeign(context, builder);
   return builder;
}

2、loadBalance(Feign.Builder, FeignContext, HardCodedTarget)

protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
		HardCodedTarget<T> target) {
	// 子容器获取feign.Client的实现类,这是之后feign调用流程的主入口,一般实现是LoadBalancerFeignClient
	Client client = getOptional(context, Client.class);
	if (client != null) {
		builder.client(client);
		// 子容器获取Targeter对象,如果引入了Hystrix相关jar包,这里就是HystrixTargeter,否则就是DefaultTargeter
		Targeter targeter = get(context, Targeter.class);
		// 构建代理对象
		return targeter.target(this, builder, context, target);
	}
	throw new IllegalStateException(
			"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
}

  • DefaultTargeter实际是调用了Feign.Builder的target方法构建代理对象
class DefaultTargeter implements Targeter {
	@Override
	public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
			FeignContext context, Target.HardCodedTarget<T> target) {
		return feign.target(target);
	}
}

Feign.Builder.target(feign.Target)方法

 public <T> T target(Target<T> target) {
 	// 构造ReflectiveFeign
 	Feign feign = this.build();
 	// 创建代理对象
    return feign.newInstance(target);
}

1、Feign.Builder利用Builder里的属性,构造ReflectiveFeign

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);
}

2、ReflectiveFeign的三个成员变量

private final ParseHandlersByName targetToHandlersByName;
private final InvocationHandlerFactory factory;
private final QueryMapEncoder queryMapEncoder;
  • InvocationHandlerFactory

JDKInvocationHandler工厂,默认实现是feign.InvocationHandlerFactory.Default,作用就是通过目标对象和Handler的映射关系,生成InvocationHandler:feign.ReflectiveFeign.FeignInvocationHandler

static final class Default implements InvocationHandlerFactory {
	// target:HardCodedTarget(FeignClientFactoryBean#getTarget里new的一个对象,[type=SpecificationStockClient, name=trade-service, url=http://trade-service])
	// dispatch:目标方法和实际方法处理器的一个mapping关系,通过变量名可以看出FeignInvocationHandler并不实际执行代理逻辑,而是根据method分发给不同的MethodHandler处理
    // 通过method实例可以直接找到MethodHandler,最后通过MethodHandler的invoke方法,实际执行代理逻辑
	@Override
	public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
	  return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
	}
}
  • QueryMapEncoder

默认实现是FieldQueryMapEncoder,作用是解析被@SpringQueryMap修饰(默认,使用SpringMvcContract)或被@QueryMap修饰(如果Spring子容器里Contract的实现是feign.Contract.Default)的方法参数,解析为一个map,这个map就是以后组装到url里成为queryParam。这里给个案例,源码解析就省略了,无非是一些反射。 案例:转换后请求的uri是/getStockByMpId/2?id=222。

@FeignClient(name = "trade-service", contextId = "override-trade-service2")
interface SpecificationStockClient2 {
    @RequestMapping(value = "/getStockByMpId/{mpId}", method = RequestMethod.GET)
    ApiResponse<Stock> getStock2(@Param("mpId") Long mpId, @SpringQueryMap(encoded = false) StockQueryParam param);
}
class StockQueryParam {
    private Long id;

    public StockQueryParam(Long id) {
        this.id = id;
    }
}
@Test
public void test01() {
    ApiResponse<Stock> stock2 = specificationStockClient.getStock2(2L, new StockQueryParam(222L));
}
  • ParseHandlersByName

封装了FeignClient类级别的配置,包括Contract、Options等。为了之后给每个方法Handler构造做准备。

static final class ParseHandlersByName {
	private final Contract contract;
	private final Options options;
	private final Encoder encoder;
	private final Decoder decoder;
	private final ErrorDecoder errorDecoder;
	private final QueryMapEncoder queryMapEncoder;
	private final SynchronousMethodHandler.Factory factory;
}

3、ReflectiveFeign.newInstance(target)

1、target:HardCodedTarget实例,封装了代理类class对象、服务名称、url。

public static class HardCodedTarget<T> implements Target<T> {
    private final Class<T> type;
    private final String name;
    private final String url;
 }

2、ReflectiveFeign的newInstance方法 创建代理对象,这里省略一些不重要的代码

@Override
public <T> T newInstance(Target<T> target) {
	// 1 调用ParseHandlersByName的apply方法,创建方法名和对应的处理Handler的映射关系
	// 方法名:SpecificationStockClient2#getStock2(Long,StockQueryParam) 
	Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
	// 2 创建method->Handler的映射
	Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
	// 循环目标对象的所有方法,放入method->Handler的映射
	for (Method method : target.type().getMethods()) {
	    methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
	}
	// 3 调用InvocationHandlerFactory.Default的create方法
	// 用目标对象和methodToHandler映射关系创建InvocationHandler
	InvocationHandler handler = factory.create(target, methodToHandler);
	// 4 创建JDK动态代理
	T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
	    new Class<?>[] {target.type()}, handler);
	return proxy;
}

ParseHandlersByName的apply方法

public Map<String, MethodHandler> apply(Target target) {
	  // 用SpringMvcContract解析目标类的所有方法,并抽象为MethodMetadata列表返回
      List<MethodMetadata> metadata = contract.parseAndValidateMetadata(target.type());
      // 构建方法名->处理Handler的映射关系
      Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
      for (MethodMetadata md : metadata) {
      	// 一对if/else获取BuildTemplate
        BuildTemplateByResolvingArgs buildTemplate = ...;
        // 构建映射
        // 这里MethodHandler的实现是由SynchronousMethodHandler.Factory#create创建的SynchronousMethodHandler实例,也就是说以后运行起来肯定能走SynchronousMethodHandler#invoke方法
        result.put(md.configKey(),
              factory.create(target, md, buildTemplate, options, decoder, errorDecoder));
      }
      return result;
    }
  }

InvocationHandler的实现是ReflectiveFeign.FeignInvocationHandler

# InvocationHandlerFactory.Default
static final class Default implements InvocationHandlerFactory {
	@Override
	public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
	  return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
	}
}

四、Feign动态代理创建流程总结

  • @EnableFeignClients
  • FeignClientsRegistrar扫描并注入FeignClientFactoryBean
  • FeignClientFactoryBean.getObject
    • 利用Spring父容器和子容器创建Feign.Builder
    • 子容器的Targeter对象,利用Feign.Builder和HardCodedTarget创建实际代理对象
      • Feign.Builder.build()构建ReflectiveFeign
      • ReflectiveFeign.newInstance通过JDK动态代理创建代理对象

五、简单实现

@EnableMyFeignClients

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyFeignClientsRegistrar.class)
public @interface EnableMyFeignClients {
    String[] value() default {};
}

@MyFeignClient

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyFeignClient {
    String value() default "";
}

MyFeignClientsRegistrar

public class MyFeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    private ResourceLoader resourceLoader;
    private Environment environment;
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 创建扫描器
        ClassPathScanningCandidateComponentProvider scanner = getScanner();
        scanner.setResourceLoader(this.resourceLoader);
        AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(MyFeignClient.class);
        scanner.addIncludeFilter(annotationTypeFilter);
        // 查找扫描包集合
        Map<String, Object> attrs = importingClassMetadata.getAnnotationAttributes(EnableMyFeignClients.class.getName());
        if (attrs == null) {
            return;
        }
        String[] packages = (String[]) attrs.get("value");
        if (packages.length == 0) {
            packages = getDefaultPackages(importingClassMetadata);
        }
        for (String p : packages) {
            // 扫描
            Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(p);
            for (BeanDefinition candidateComponent : candidateComponents) {
                if (candidateComponent instanceof AnnotatedBeanDefinition) {
                    AnnotatedBeanDefinition bd = (AnnotatedBeanDefinition) candidateComponent;
                    AnnotationMetadata annotationMetadata = bd.getMetadata();
                    // 注册FactoryBean
                    registerFeignClient(registry, annotationMetadata);
                }
            }
        }
    }
	// 注册MyFeignClientFactoryBean
    private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata) {
        Map<String, Object> annotationAttributes = annotationMetadata.getAnnotationAttributes(MyFeignClient.class.getName());
        if (annotationAttributes == null)
            return;
        BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(MyFeignClientFactoryBean.class);
        definitionBuilder.addPropertyValue("type", annotationMetadata.getClassName());
        definitionBuilder.addPropertyValue("name", (String) annotationAttributes.get("value"));
        AbstractBeanDefinition beanDefinition = definitionBuilder.getBeanDefinition();
        registry.registerBeanDefinition(annotationMetadata.getClassName(), beanDefinition);
    }

    // 取注解所在类所在包作为扫描路径
    private String[] getDefaultPackages(AnnotationMetadata importingClassMetadata) {
        String className = importingClassMetadata.getClassName();
        int lastDotIndex = className.lastIndexOf(".");
        return lastDotIndex != -1 ? new String[]{className.substring(0, lastDotIndex)} : new String[]{};
    }

    private ClassPathScanningCandidateComponentProvider getScanner() {
        return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                // 目标beanDefinition必须是顶层类(不依赖与其他类isIndependent)且不能是注解
                return beanDefinition.getMetadata().isIndependent() && !beanDefinition.getMetadata().isAnnotation();
            }
        };
    }
    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
}

MyFeignClientFactoryBean

public class MyFeignClientFactoryBean implements FactoryBean<Object>, ApplicationContextAware {
    // 目标对象(FeignClient接口)
    private Class<?> type;
    // 服务名称
    private String name;
    private ApplicationContext applicationContext;
    @Override
    public Object getObject() throws Exception {
        FeignContext feignContext = applicationContext.getBean(FeignContext.class);
        // 1. 通过子容器创建Feign.Builder
        Feign.Builder builder = getFeignBuilder(feignContext);
        System.out.println(builder.getClass());// Feign.Builder
        // 省略获取Targeter对象,通过Targeter.target方法创建动态代理的过程,因为Targeter不是public的
        // 2. build构造ReflectiveFeign
        Feign feign = builder.build();
        System.out.println(feign.getClass());// ReflectiveFeign
        // 3. ReflectiveFeign.newInstance创建代理对象
        return feign.newInstance(new Target.HardCodedTarget<>(this.type, this.name, "http://" + this.name));
    }
    private Feign.Builder getFeignBuilder(FeignContext feignContext) {
        FeignLoggerFactory loggerFactory = feignContext.getInstance(this.name, FeignLoggerFactory.class);
        Logger logger = loggerFactory.create(this.type);
        Feign.Builder builder = feignContext.getInstance(this.name, Feign.Builder.class);
        builder.logger(logger)
                .decoder(feignContext.getInstance(this.name, Decoder.class))
                .encoder(feignContext.getInstance(this.name, Encoder.class))
                .contract(feignContext.getInstance(this.name, Contract.class))
                .client(feignContext.getInstance(this.name, Client.class));
        return builder;
    }
    @Override
    public Class<?> getObjectType() {
        return this.type;
    }
    public void setType(Class<?> type) {
        this.type = type;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}