SpringCloud源码解读【01】-OpenFeign

一、Open Feign

声明式 RESTful客户端;类似于 RestTemplateOpenFeign是对 JDKHttpURLConnection(以及第三方库 HttpClient 和 OkHttp)的包装和简化,并且还自动整合了 Ribbon

OpenFeign会完全代理 HTTP 的请求,在使用过程中我们只需要依赖注入 Bean,然后调用对应的方法传递参数即可。

Feign的第一个目标是减少HTTP API的复杂性,希望能将HTTP调用做到像RPC一样易用;

这对程序员而言屏蔽了 HTTP 的请求响应过程,让代码更趋近于『调用』的形式。

1.FeignOpenfeign 的区别

Feign 最早是由 Netflix 公司进行维护的,后来 Netflix不再对其进行维护,最终 Feign 由社区进行维护,更名为 Openfeign

2.Feign的底层原理

基于jdk的动态代理和接口的本地化,做的服务调用;

从官方文档的Feign功能手册,我们可以知道,要想使用需要做以下的步骤

  • 引用Feign组件包starter
  • 编写client类【即定义FeignAPI接口】
  • 调用服务开启Feign Client注解,并声明需要扫描的包,即可以接口形式做http远程调用

1.注册 FeignClient接口

1.@EnableFeignClient

在解析这个注解之前,做了一件事,就是@Import(FeignClientsRegistrar.class)这个注册器;单击这个类查看调用方发现,只有一个地方用了它,并且很巧,就是FeignClientsRegistrar这个类;

@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

ImportBeanDefinitionRegistrar的子类,这会使容器初始化时,运行FeignClient的注册方法;

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

它做了两件事情:注册类的默认定义信息;注册Feign Client的定义信息【后续依据定义初始化bean】;

2.获取代理对象

1.FeignClientFactoryBean

@FeignClient修饰的接口的实际初始化的bean工厂;生产Feign对象

扫描二维码关注公众号,回复: 16706132 查看本文章

在看这个工厂之前,先看下顶级父类FactoryBean

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

通过源码可以知道,默认的feign是没有降级策略和降级工厂的;估计是直接抛出异常了;

再看看FeignClient的工厂beans,基本上可以确定,获取bean的核心方法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

启动时,会初始化Feign配置信息,并注入一个上下文bean;

FeignAutoConfiguration有初始化;另外,spring.facotries中又有对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

Feign 发送请求以及接收响应等都是由 Client完成,该类默认 Client.Default,另外支持 HttpClient、OkHttp等客户端;

再看一下FeignClientFactoryBean的负载策略;

// 负载调用核心流程:获取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

Target有2个实现类,在没有配置Hystrix插件的时候,是默认使用的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

至此,我们找到了核心的返回对象ReflectiveFeign

并且,可以发现,实际上返回的Feign对象,其实是一个动态代理通过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

其实是ReflectiveFeign类部的一个静态类;

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

也就是说,此处的代理,返回的实际是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.Http调用

再返回看Feign类的源码;

回到Feign

buid方法中这一段很重要;

// 这个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);

可以看到,使用工厂方法创建的处理器传了一个参数,它是SynchronousMethodHandler类型的;很巧,它也是一个动态代理的一个处理器;

但是我们之前的源码,读到这一行源码【``InvocationHandler handler = factory.create(target, methodToHandler);】时,给的解释是,返回的命名是FeignInvokeHandler,那既然处理器是它,proxy代理对象执行的时候,那也应该是看这个里面的invoke`方法;

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

看着不太像,里面也没有远程调用的相关代码;

但是dispatch,这个是创建工厂时,做了初始化的赋值,它是SynchronousMethodHandler类型;

而且这里面它很有意思,它返回的值,是调用SynchronousMethodHandler对象的invoke方法,注意,这块可不是代理,而是简单的方法调用;

因为如果是jdk的代理,invoke必须由三个参数:代理对象、代理对象的接口方法,代理对象的接口方法参数

public Object invoke(Object proxy, Method method, Object[] args){
    
    } 
SynchronousMethodHandler
  • RequestTemplate:构建 Request模版类
  • Options:存放连接、超时时间等配置类
  • Retryer:失败重试策略类
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.面试口述

1.从使用上来说,我们编写feign接口,必定需要去做controller的接口层面定义,即接口的本地化;

2.从@EnableFeignClient开始,通过Feign组件提供的spring.factories机制,自动注入和初始化FeignClientRegistrar,这就保证了对FeigClient包路径的解析,再到定义FeignClient的工厂类FeignClientFactoryBean,基本上我们编写的接口和配置,已经可以让Spring容器对他们进行管理了;

3.通过Feign集成的Ribbon插件,可以帮助我们从注册中心获取到不同的服务信息,并且允许我们使用一些负载策略。这就保证了接口在服务之间的路由问题;

4.那么我们在代码里面调用这些feign接口的时候,实际上是通过jdk的动态模式去操作的,通过调用接口,直接会触发动态代理机制,执行对应的反射处理器InnovocationHandler,来获取代理对象;

5.对于openFeign来说,它这里封装了动态代理FeignInvocationHandler,初始化时,定义好了【方法->方法处理器】的map映射信息,通过代理机制,在触发调用时,自动调用invoke方法,来拿到方法处理器,并再做一次invoke调用【此处invoke不是代理】,最终将我们在FeignClient上面的配置,这就包括服务名的解析、还有uri的解析,这里面Feign组件使用的都是顶级的父类ClientTarget,并且提供默认的处理机制,和可扩展的okhttp以及hystrix机制,再配合ribbon在注册中心找到相关服务的信息,配合uri转义成http接口到具体服务的本地接口调用;

这样整个流程就结束了!里面设计的非常巧妙,在整个过程中,并没有实际的方法调用,但是通过动态代理的invoke机制,帮助我们完成了整个服务的调用;

这块代码比较绕,而且需要对jdk动态代理非常熟悉才行,如果不熟悉的话,会被绕进去;

代理对象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");
    }
}

处理器FeignInvocationHandler

代理

Proxy.newProxyInstance方法参数说明:代理对象的类加载器、代理对象的接口、代理的处理器(继承jdkInvocationHandler,并重写invoke方法)

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

5.扩展源码

注意,FeignClientRegistrar的顶级父类ImportBeanDefinitionRegistrar,这将会在容器的启动中的invokeBeanFactoryPostProcessors(beanFactory);

这一步里面,是Srping开放给开发者,允许我们对注册的定义信息做控制,这意味着我们定义的接口在这个规则下操作,可以被Spring管理;

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

猜你喜欢

转载自blog.csdn.net/u013553309/article/details/122587195