SpringCloud source code interpretation【01】-OpenFeign

一、Open Feign

Declarative RESTfulclient; similar RestTemplate, OpenFeignis a wrapper and simplification of Python JDK( HttpURLConnectionand third-party libraries HttpClient 和 OkHttp) and also automatically integrates it Ribbon.

OpenFeignIt will completely proxy HTTP requests. During use, we only need dependency injection Bean, and then call the corresponding method to pass parameters.

FeignThe first goal is to reduce HTTP APIthe complexity, hoping to make HTTP calls as easy to use as RPC ;

For programmers, this shields the HTTP request response process and makes the code closer to the form of "call".

1.The difference between FeignandOpenfeign

Feign was first maintained by Netflix , but later Netflixit was no longer maintained. Finally, Feign was maintained by the community and renamedOpenfeign

2. FeignThe underlying principle of

Based on jdkthe localization of dynamic proxy and interface, make service calls;

From Feignthe function manual of the official document, we can know that in order to use it, we need to do the following steps

  • Reference Feigncomponent packagestarter
  • Write clienta class [i.e. defined Feigninterface API]
  • Call the service to enable Feign Clientannotations and declare the packages that need to be scanned, that is, httpremote calls can be made in the form of interfaces.

1.Registration FeignClientinterface

1.@EnableFeignClient

Before parsing this annotation, one thing was done, which is @Import(FeignClientsRegistrar.class)this register; click this class to view the caller and found that it is only used in one place, and coincidentally, it is FeignClientsRegistrarthis class;

@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 {
    
    };
}
2.FeignClientsRegistrar

ImportBeanDefinitionRegistrarsubclass, which will cause FeignClientthe registration method to be run when the container is initialized;

class FeignClientsRegistrar
		implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    
    
    .....
    @Override
	public void registerBeanDefinitions(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
    
    
        // 注册FeignClient客户端的默认配置信息
		registerDefaultConfiguration(metadata, registry);
        // 注册Feign Client客户端
		registerFeignClients(metadata, registry);
	}
	public void registerFeignClients(AnnotationMetadata metadata,
		BeanDefinitionRegistry registry) {
    
    
		Map<String, Object> attrs = metadata
				.getAnnotationAttributes(EnableFeignClients.class.getName());
        // 注解类型过滤器,只扫描@FeignClient注解的接口
		AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
    	// 扫描EnableFeignClient注解定义的feign client所有包路径
		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();
                // 校验@FeignClient修饰的类,必须是接口interface
				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"));
                // 真正注册feign client的地方
				registerFeignClient(registry, annotationMetadata, attributes);
			}
		}
	}
    // 真正注册feign client的地方,解析@FeignClient注解的配置信息,并且利用builder【FeignClientFactoryBean】进行构建client的定义信息
	private void registerFeignClient(BeanDefinitionRegistry registry,
		AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
    
    
		String className = annotationMetadata.getClassName();
        // bean定义构建器:FeignClientFactoryBean.class,定义好解析的信息后,后续spring容器将根据此构建器初始化bean
		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);
		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();
		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);
	}
}	

It does two things: register the default definition information of the class; register Feign Clientthe definition information [subsequent initialization based on the definition bean];

2. Get the proxy object

1.FeignClientFactoryBean

@FeignClientThe actual initialization beanfactory of the modified interface; the production Feignobject

Before looking at this factory, let’s take a look at the top-level parent classFactoryBean

public interface FactoryBean {
    
    
    private Class<?> type;
	private String name;
	private String url;
	private String contextId;
	private String path;
	private boolean decode404;
	private ApplicationContext applicationContext;
	private Class<?> fallback = void.class;
	private Class<?> fallbackFactory = void.class;
    ...
    @Nullable
	T getObject() throws Exception;
    @Nullable
	Class<?> getObjectType();
    default boolean isSingleton() {
    
    
		return true;
	}
}

From the source code, we can know that the default feignis no downgrade strategy and downgrade factory; it is estimated that an exception is thrown directly;

FeignClientLooking at the factory again beans, we can basically determine beanthe core method of acquisition getObject();

class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
    
    
    @Override
    public Object getObject() throws Exception {
    
    
        return getTarget();
    }
    /**
     * @param <T> the target type of the Feign client
     * @return a {@link Feign} client created with the specified data and the context
     * information
     */
    <T> T getTarget() {
    
    
        // 从 IOC 容器获取 FeignContext,看第二步【FeignContext】
        FeignContext context = this.applicationContext.getBean(FeignContext.class);
        // 通过 context 创建 Feign 构造器
        Feign.Builder builder = feign(context);
        // 没有配置url,通过ribbon在注册中心获取服务
        if (!StringUtils.hasText(this.url)) {
    
    
            if (!this.name.startsWith("http")) {
    
    
                this.url = "http://" + this.name;
            }
            else {
    
    
                this.url = this.name;
            }
            this.url += cleanPath();
            // 负载调用核心流程【1】
            return (T) loadBalance(builder, context,
                    new HardCodedTarget<>(this.type, this.name, this.url));
        }
        // 如果配置了url,则直接走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 load 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 (T) targeter.target(this, builder, context,new HardCodedTarget<>(this.type, this.name, url));
    }
    // 负载调用核心流程【2】:获取client对象--->调用
    protected <T> T loadBalance(Feign.Builder builder, FeignContext context,HardCodedTarget<T> target) {
    
    
        // 获取客户端类型,看第三步【Client】
        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);
        }
        throw new IllegalStateException(
            "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
    }
}
2.FeignContext

At startup, Feignconfiguration information will be initialized and a context will be injected bean;

FeignAutoConfigurationThere is initialization in ; in addition, there is startup configuration spring.facotriesin ;FeignAutoConfiguration

@Configuration
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({
    
     FeignClientProperties.class,FeignHttpClientProperties.class })
public class FeignAutoConfiguration {
    
    

	@Autowired(required = false)
	private List<FeignClientSpecification> configurations = new ArrayList<>();

	@Bean
	public HasFeatures feignFeature() {
    
    
		return HasFeatures.namedFeature("Feign", Feign.class);
	}

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

FeignSending requests and receiving responses are all Clientcompleted by this class by default Client.Default, and it also supports HttpClient、OkHttpother clients;

Let’s take another look at FeignClientFactoryBeanthe load strategy;

// 负载调用核心流程:获取client对象--->调用
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,HardCodedTarget<T> target) {
    
    
    // 获取客户端类型,client如果没有配置第三方则使用默认的Client【feign包下】
	Client client = getOptional(context, Client.class);
	if (client != null) {
    
    
        // 设置客户端类型
		builder.client(client);
        // Target也是如此,此处使用默认的feign包下的Targeter
		Targeter targeter = get(context, Targeter.class);
        // 核心流程:看下面第四步【Target】源码
		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?");
}
4.Target

TargetThere are 2 implementation classes, which Hystrixare used by default when no plug-in is configured.DefaultTargeter

interface Targeter {
    
    
	<T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
			FeignContext context, Target.HardCodedTarget<T> target);
}
class DefaultTargeter implements Targeter {
    
    
	@Override
	public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
			FeignContext context, Target.HardCodedTarget<T> target) {
    
    
        // 接第三步【Target】的targeter.target(this, builder, context, target);
        // 直接走向地5步【feign】
		return feign.target(target);
	}
}
class HystrixTargeter implements Targeter {
    
    
	@Override
	public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
			FeignContext context, Target.HardCodedTarget<T> target) {
    
    
		if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
    
    
			return feign.target(target);
		}
		feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
		SetterFactory setterFactory = getOptional(factory.getName(), context,
				SetterFactory.class);
		if (setterFactory != null) {
    
    
			builder.setterFactory(setterFactory);
		}
		Class<?> fallback = factory.getFallback();
		if (fallback != void.class) {
    
    
			return targetWithFallback(factory.getName(), context, target, builder,
					fallback);
		}
		Class<?> fallbackFactory = factory.getFallbackFactory();
		if (fallbackFactory != void.class) {
    
    
			return targetWithFallbackFactory(factory.getName(), context, target, builder,
					fallbackFactory);
		}
		return feign.target(target);
	}
    ....
}
5.Feign
public abstract class Feign {
    
    

	public static Builder builder() {
    
    
    	return new Builder();
  	}
    
    // 接第四步的方法
	public <T> T target(Target<T> target) {
    
    
  		return build().newInstance(target);
	}
    
    public Feign build() {
    
    
      // 这一行,非常之重要
      SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
          new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
              logLevel, decode404, closeAfterDecode, propagationPolicy);
      ParseHandlersByName handlersByName =
          new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
              errorDecoder, synchronousMethodHandlerFactory);
      // 找到了,ReflectiveFeign,看第六步【ReflectiveFeign】,获取到对象后,再调用其instance方法,对应:build().newInstance(target);
      return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
    }
}
6.ReflectiveFeign

At this point, we have found the core return objectReflectiveFeign

Moreover, it can be found that the object returned is actually obtained Feignby a dynamic proxy through the method;newInstance()

public class ReflectiveFeign extends Feign {
    
    

  	private final ParseHandlersByName targetToHandlersByName;
  	private final InvocationHandlerFactory factory;
  	private final QueryMapEncoder queryMapEncoder;
    
	// 接第五步的的代码: new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder)
  	ReflectiveFeign(ParseHandlersByName targetToHandlersByName, InvocationHandlerFactory factory,
      	QueryMapEncoder queryMapEncoder) {
    
    
    	this.targetToHandlersByName = targetToHandlersByName;
    	this.factory = factory;
    	this.queryMapEncoder = queryMapEncoder;
  	}
    
    // 再返回到第五步【Feign】的代码:build().newInstance(target);
    @Override
    public <T> T newInstance(Target<T> target) {
    
    
      // 1.处理 @FeignCLient 注解(SpringMvc 注解等)封装为 MethodHandler 包装类
      Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
      Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
      List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
      // 2.遍历接口中所有方法,过滤 Object 方法,并将默认方法以及 FeignClient 方法分类
      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)));
        }
      }
      // 3.通过工厂方法create(),返回代理对象,看第七步【FeignInvocationHandler】
      InvocationHandler handler = factory.create(target, methodToHandler);
      T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[] {
    
    target.type()}, handler);
      // 4.接口内 default 方法 绑定动态代理类
      for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
    
    
       	 defaultMethodHandler.bindTo(proxy);
      }
      return proxy;
    }
}
7.FeignInvocationHandler

In fact, it is ReflectiveFeigna static class in the class department;

InvocationHandler handler = factory.create(target, methodToHandler);

In other words, the proxy here actually returns FeignInvocationHandler;

static class FeignInvocationHandler implements InvocationHandler {
    
    

    private final Target target;
    private final Map<Method, MethodHandler> dispatch;

    FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) {
    
    
      this.target = checkNotNull(target, "target");
      this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
      if ("equals".equals(method.getName())) {
    
    
        try {
    
    
          Object otherHandler =
              args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
          return equals(otherHandler);
        } catch (IllegalArgumentException e) {
    
    
          return false;
        }
      } else if ("hashCode".equals(method.getName())) {
    
    
        return hashCode();
      } else if ("toString".equals(method.getName())) {
    
    
        return toString();
      }

      return dispatch.get(method).invoke(args);
    }
}

3. HttpCall

Then go back and look at Feignthe source code of the class;

return toFeign

buidThis section of the method is very important;

// 这个synchronousMethodHandlerFactory将会是jdk代理最终的处理器
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory = 
    new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
              logLevel, decode404, closeAfterDecode, propagationPolicy);
ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
              errorDecoder, synchronousMethodHandlerFactory);
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);

As you can see, the processor created using the factory method passes a parameter, which is SynchronousMethodHandlerof type; coincidentally, it is also a processor of a dynamic proxy;

But in our previous source code, we read this line of source code [``InvocationHandler handler = factory.create(target, methodToHandler); 】时,给的解释是,返回的命名是FeignInvokeHandler ,那既然处理器是它,proxy 代理对象执行的时候,那也应该是看这个里面的invoke` method;

static class FeignInvocationHandler implements InvocationHandler {
    
    

    private final Target target;
    private final Map<Method, MethodHandler> dispatch;

    FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) {
    
    
      this.target = checkNotNull(target, "target");
      this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
      if ("equals".equals(method.getName())) {
    
    
        try {
    
    
          Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
          return equals(otherHandler);
        } catch (IllegalArgumentException e) {
    
    
          return false;
        }
      } else if ("hashCode".equals(method.getName())) {
    
    
        return hashCode();
      } else if ("toString".equals(method.getName())) {
    
    
        return toString();
      }

      return dispatch.get(method).invoke(args);
    }
}

It doesn’t look like it, and there is no code related to remote calling;

However dispatch, this is an initialized assignment when the factory is created, and it is SynchronousMethodHandlera type;

And it's very interesting here. The value it returns is the method SynchronousMethodHandlerof calling the object invoke. Note that this is not a proxy, but a simple method call;

Because if it is jdka proxy, invokeit must have three parameters: the proxy object, the interface method of the proxy object, and the interface method parameters of the proxy object.

public Object invoke(Object proxy, Method method, Object[] args){
    
    } 
SynchronousMethodHandler
  • RequestTemplate:Build Requesttemplate class
  • Options:Storage configuration classes such as connection and timeout time
  • Retryer:Failure retry strategy class
final class SynchronousMethodHandler implements MethodHandler {
    
    

  private static final long MAX_RESPONSE_BUFFER_SIZE = 8192L;
  private final MethodMetadata metadata;
  // jdk动态代理的目标类
  private final Target<?> target;
  private final Client client;
  private final Retryer retryer;
  private final List<RequestInterceptor> requestInterceptors;
  ...  
  ...  
  private final List<RequestInterceptor> requestInterceptors;
  ...  
  ...  
  private final RequestTemplate.Factory buildTemplateFromArgs;
  ...  
  ...  
      
  // 获取代理对象后,代理执行的核心方法
  @Override
  public Object invoke(Object[] argv) throws Throwable {
    
    
    RequestTemplate template = buildTemplateFromArgs.create(argv);
    Retryer retryer = this.retryer.clone();
    while (true) {
    
    
      try {
    
    
        // 执行调用逻辑
        return executeAndDecode(template);
      } catch (RetryableException e) {
    
    
        try {
    
    
          // 控制重试次数
          retryer.continueOrPropagate(e);
        } catch (RetryableException th) {
    
    
          Throwable cause = th.getCause();
          if (propagationPolicy == UNWRAP && cause != null) {
    
    
            throw cause;
          } else {
    
    
            throw th;
          }
        }
        if (logLevel != Logger.Level.NONE) {
    
    
          logger.logRetry(metadata.configKey(), logLevel);
        }
        continue;
      }
    }
  }
  ...  
  ...  
 // 核心远程调用的逻辑
 Object executeAndDecode(RequestTemplate template) throws Throwable {
    
    
    // 1.循环执行fein的拦截器
    Request request = targetRequest(template);

    if (logLevel != Logger.Level.NONE) {
    
    
      logger.logRequest(metadata.configKey(), logLevel, request);
    }

    Response response;
    long start = System.nanoTime();
    try {
    
    
      // 2.远程调用
      response = client.execute(request, options);
    } catch (IOException e) {
    
    
      if (logLevel != Logger.Level.NONE) {
    
    
        logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
      }
      throw errorExecuting(request, e);
    }
    long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);

    boolean shouldClose = true;
    // 3.处理接口响应
    try {
    
    
      if (logLevel != Logger.Level.NONE) {
    
    
        response =
            logger.logAndRebufferResponse(metadata.configKey(), logLevel, response, elapsedTime);
      }
      if (Response.class == metadata.returnType()) {
    
    
        if (response.body() == null) {
    
    
          return response;
        }
        if (response.body().length() == null ||
            response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
    
    
          shouldClose = false;
          return response;
        }
        // Ensure the response body is disconnected
        byte[] bodyData = Util.toByteArray(response.body().asInputStream());
        return response.toBuilder().body(bodyData).build();
      }
      if (response.status() >= 200 && response.status() < 300) {
    
    
        if (void.class == metadata.returnType()) {
    
    
          return null;
        } else {
    
    
          Object result = decode(response);
          shouldClose = closeAfterDecode;
          return result;
        }
      } else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {
    
    
        Object result = decode(response);
        shouldClose = closeAfterDecode;
        return result;
      } else {
    
    
        throw errorDecoder.decode(metadata.configKey(), response);
      }
    } catch (IOException e) {
    
    
      if (logLevel != Logger.Level.NONE) {
    
    
        logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime);
      }
      throw errorReading(request, response, e);
    } finally {
    
    
      if (shouldClose) {
    
    
        ensureClosed(response.body());
      }
    }
  }
}

4. Interview narration

1. In terms of usage, when we write feignan interface, we must controllerdefine the interface level, that is, the localization of the interface;

2. From @EnableFeignClientthe beginning, through the mechanism Feignprovided by the component , automatic injection and initialization are ensured, which ensures the analysis of the package path, and then to the defined factory class . Basically, the interface and configuration we wrote can already allow the container to manage them. Already;spring.factoriesFeignClientRegistrarFeigClientFeignClientFeignClientFactoryBeanSpring

3. The Feignintegrated Ribbonplug-in can help us obtain different service information from the registration center and allow us to use some load strategies. This ensures that the interface is routed between services;

4. When we call these interfaces in the code feign, we actually jdkoperate through the dynamic mode. By calling the interface, the dynamic proxy mechanism will be directly triggered, and the corresponding reflection processor will be executed InnovocationHandlerto obtain the proxy object;

5. For openFeign, it encapsulates a dynamic proxy FeignInvocationHandler. During initialization, the mapping information of [Method -> Method Processor] is defined. mapThrough the proxy mechanism, when the call is triggered, invokethe method is automatically called to get the method processor. , and make another invokecall [this invokeis not a proxy], and finally configure our FeignClientabove configuration, which includes the resolution of service names and other uriresolutions. The components here Feignuse the top-level parent class Clientand Targetprovide default The processing mechanism and extensible okhttp以及hystrixmechanism are combined with ribbonfinding the relevant service information in the registration center and escaping urithe httpinterface into a local interface call for the specific service;

This completes the process! The design is very clever. In the whole process, there is no actual method call, but through the dynamic proxy invokemechanism, it helps us complete the call of the entire service;

This piece of code is quite convoluted, and you need to be jdk动态代理very familiar with it. If you are not familiar with it, you will be circumvented;

Proxy object :HardCodedTarget

public static class HardCodedTarget<T> implements Target<T> {
    
    

    private final Class<T> type;
    private final String name;
    private final String url;

    public HardCodedTarget(Class<T> type, String url) {
    
    
      this(type, url, url);
    }

    public HardCodedTarget(Class<T> type, String name, String url) {
    
    
      this.type = checkNotNull(type, "type");
      this.name = checkNotNull(emptyToNull(name), "name");
      this.url = checkNotNull(emptyToNull(url), "url");
    }
}

Processor :FeignInvocationHandler

acting

Proxy.newProxyInstanceMethod parameter description: class loader of proxy object, interface of proxy object, processor of proxy (inherited jdk, InvocationHandlerand overridden invokemethod)

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

5.Extended source code

Note that FeignClientRegistrarthe top-level parent classImportBeanDefinitionRegistrar ofinvokeBeanFactoryPostProcessors(beanFactory);

This step is Srpingopen to developers, allowing us to control the registered definition information, which means that the interface we define operates under this rule and can be Springmanaged;

@Override
public void refresh() throws BeansException, IllegalStateException {
    
    
	synchronized (this.startupShutdownMonitor) {
    
    
		// 准备,记录容器的启动时间startupDate, 标记容器为激活,初始化上下文环境如文件路径信息,验证必填属性是否填写
		prepareRefresh();
		// 创建容器DefaultListableBeanFactory, 接着扫描classpath路径下的所有的Bean信息,并生成对应的BeanDefinition
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		// 设置beanFactory类加载器,添加多个beanPostProcesser
		prepareBeanFactory(beanFactory);
		try {
    
    
			// 这个方法是个空实现,但是web模块中使用这个注入web的一些特有的ServletContextAwareProcessor实现类
			postProcessBeanFactory(beanFactory);
			// 调用BeanFactoryPostProcessor各个实现类的方法:允许用户自定义改变bean的定义信息
			invokeBeanFactoryPostProcessors(beanFactory);
			// 注册BeanPostProcessor的实现类。 在bean创建过程中调用
			registerBeanPostProcessors(beanFactory);
			// 初始化国际化的资源信息放入容器中
			initMessageSource();
			// 初始化spring的消息监听器
			initApplicationEventMulticaster();
			// 在这个子类中,这个方法被用来 初始化WebServer, 并启动服务。 tomcat就是在这里启动
			onRefresh();
			// 注册事件监听器
			registerListeners();
			// 实例化所有单利的bean信息,不包括lazy-init的
			finishBeanFactoryInitialization(beanFactory);
			// 这里会清空一些只在启动中有用的缓存信息,广播启动成功的事件
			finishRefresh();
		}
		catch (BeansException ex) {
    
    
			if (logger.isWarnEnabled()) {
    
    
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}
			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();
			// Reset 'active' flag.
			cancelRefresh(ex);
			// Propagate exception to caller.
			throw ex;
		}
		finally {
    
    
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}
}

Guess you like

Origin blog.csdn.net/u013553309/article/details/122587195