SpringCloud Feign 原理分析

目的

分析feign 调用的过程

源码分析

FeignAutoConfiguration承担了feign业务的自动配置的功能

从这个类中类中大致可以观察到加载的类
FeignContext: feign的上下文环境 依赖的FeignClientsConfiguration我们可以进一步的进入这个类来看看
有fegin的编码,解码, 转换器service, 依赖的hystrix 等等...
   
 
OkHttpClient 提供http发送的底层工具

然后就是自动配置了一个Targeter的bean, 这是干什么的呢? 进一步的debug

在实现类HystrixTargeter的内部方法target加上端点 启动项目我们从debug试图来看看当前调用链如下:

doGetBean-->getObjectForBeanInstance-->doGetObjectFromFactoryBean-->getObject-->loadBalance-->target

bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
beanName 是com.example.demo.ScheduleService

loadBalance部分targeter.target(this, builder, context, target)
targeter对象是 HystrixTargeter对象

所以可以判断的是在spring 初始化我们自定义的service Bean ScheduleService 的时候, 扫描到改组件使用了@FeignClient注解
所以需要为该类添加一个负载均衡的调用的策略, 调用loadBalance 方法 这个就和好理解了, 我们进一步通过debug代码来看
class FeignClientsConfigutation{
    
    //feignHystrixBuilder fein 需要使用到hystrix
    @Configuration
    @ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
    protected static class HystrixFeignConfiguration {
        @Bean
        @Scope("prototype")
        @ConditionalOnMissingBean
        @ConditionalOnProperty(name = "feign.hystrix.enabled")
        public Feign.Builder feignHystrixBuilder() {
            return HystrixFeign.builder();
        }
    }
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
//注册类 扫描组件
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
    
}

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
		ResourceLoaderAware, EnvironmentAware {

	@Override
	public void setResourceLoader(ResourceLoader resourceLoader) {
		this.resourceLoader = resourceLoader;
	}

    //扫描加了容器
	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
	    //扫描@EnableFeignClients 
		registerDefaultConfiguration(metadata, registry);
	    //扫描@FeignClient
		registerFeignClients(metadata, registry);
	}

}	

@EnableConfigurationProperties({FeignClientProperties.class, FeignHttpClientProperties.class})
public class FeignAutoConfiguration {
    
    //配置feign的上线文
	@Bean
	public FeignContext feignContext() {
		FeignContext context = new FeignContext();
		context.setConfigurations(this.configurations);
		return context;
	}
	
	@Configuration
    @ConditionalOnClass(name = "feign.hystrix.HystrixFeign")
    protected static class HystrixFeignTargeterConfiguration {
        @Bean
        @ConditionalOnMissingBean
        public Targeter feignTargeter() {
            return new HystrixTargeter();
        }
    }
}


public class FeignContext extends NamedContextFactory<FeignClientSpecification> {

    //配置feign的上下文
	public FeignContext() {
		super(FeignClientsConfiguration.class, "feign", "feign.client.name");
	}

}

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 强转为Builder对象
		feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
		SetterFactory setterFactory = getOptional(factory.getName(), context,
			SetterFactory.class);
		if (setterFactory != null) {
			builder.setterFactory(setterFactory);
		}
		//获取我们的fallback类
		Class<?> fallback = factory.getFallback();
		if (fallback != void.class) {
		    //--->
			return targetWithFallback(factory.getName(), context, target, builder, fallback);
		}
		//获取fallback工厂类
		Class<?> fallbackFactory = factory.getFallbackFactory();
		if (fallbackFactory != void.class) {
			return targetWithFallbackFactory(factory.getName(), context, target, builder, fallbackFactory);
		}
        //获取代理的target对象
		return feign.target(target);
	}
}

class HystrixFiegn{
    
    Feign build(final FallbackFactory<?> nullableFallbackFactory) {
      //super设置了一个InvocationHandlerFactory 代理处理器工厂  HystrixInvocationHandler内部需要进一步的debug
      super.invocationHandlerFactory(new InvocationHandlerFactory() {
        @Override public InvocationHandler create(Target target,
            Map<Method, MethodHandler> dispatch) {
          return new HystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory);
        }
      });
      super.contract(new HystrixDelegatingContract(contract));
      return super.build();
    }
    
    public <T> T target(Target<T> target, T fallback) {
      return build(fallback != null ? new FallbackFactory.Default<T>(fallback) : null)
          .newInstance(target);
    }
}

final class HystrixInvocationHandler implements InvocationHandler {
    public Object invoke(final Object proxy, final Method method, final Object[] args)
          throws Throwable {
        // early exit if the invoked method is from java.lang.Object
        // code is the same as ReflectiveFeign.FeignInvocationHandler
        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();
        }
    
        //如果不是equals, hashCode, toString 方法的时候
        //创建一个hystrixCommand对象, 内部重写方法run, getFallback方法
        HystrixCommand<Object> hystrixCommand = new HystrixCommand<Object>(setterMethodMap.get(method)) {
          @Override
          protected Object run() throws Exception {
            try {
                //进行方法的调用的时候是有负载均衡的 debug
              return HystrixInvocationHandler.this.dispatch.get(method).invoke(args);
            } catch (Exception e) {
              throw e;
            } catch (Throwable t) {
              throw (Error) t;
            }
          }
    
          @Override
          protected Object getFallback() {
            if (fallbackFactory == null) {
              return super.getFallback();
            }
            try {
              Object fallback = fallbackFactory.create(getExecutionException());
              Object result = fallbackMethodMap.get(method).invoke(fallback, args);
              if (isReturnsHystrixCommand(method)) {
                return ((HystrixCommand) result).execute();
              } else if (isReturnsObservable(method)) {
                // Create a cold Observable
                return ((Observable) result).toBlocking().first();
              } else if (isReturnsSingle(method)) {
                // Create a cold Observable as a Single
                return ((Single) result).toObservable().toBlocking().first();
              } else if (isReturnsCompletable(method)) {
                ((Completable) result).await();
                return null;
              } else {
                return result;
              }
            } catch (IllegalAccessException e) {
              // shouldn't happen as method is public due to being an interface
              throw new AssertionError(e);
            } catch (InvocationTargetException e) {
              // Exceptions on fallback are tossed by Hystrix
              throw new AssertionError(e.getCause());
            }
          }
        };
    
        //开始我们的hystrixCommand 的执行 , hystrix 为服务的熔断提供了保障
        if (isReturnsHystrixCommand(method)) {
          return hystrixCommand;
        } else if (isReturnsObservable(method)) {
          // Create a cold Observable
          return hystrixCommand.toObservable();
        } else if (isReturnsSingle(method)) {
          // Create a cold Observable as a Single
          return hystrixCommand.toObservable().toSingle();
        } else if (isReturnsCompletable(method)) {
          return hystrixCommand.toObservable().toCompletable();
        }
        return hystrixCommand.execute();
     }
}



public class ReflectiveFeign extends Feign {
    
    /**
    *开始创建代理对象 
    */
    public <T> T newInstance(Target<T> target) {
        Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
        Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
        List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
    
        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)));
          }
        }
        InvocationHandler handler = factory.create(target, methodToHandler);
        //熟悉的代码,高级使用, 生成一个代理对象
        T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, handler);
    
        for(DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
          defaultMethodHandler.bindTo(proxy);
        }
        return proxy;
     }
}


class HttpClientRibbonConfiguration{
    //如果没有注入retryTemplate的时候会少传递一个LoadBalancedRetryFactory
    //feign 里面是有ribbon的 , 在进行方法调用的时候会进行RibbonLoadBalancingHttpClient的初始化
    //默认的rule是ZoneAvoidanceRule, 那么如何进行自定义负载均衡的策略呢?  我们需要自动配置
    //当我们只需第一个feign请求的时候会对RibbonLoadBalancingHttpClient进行初始化
    @Bean
    @ConditionalOnMissingBean(AbstractLoadBalancerAwareClient.class)
    @ConditionalOnMissingClass(value = "org.springframework.retry.support.RetryTemplate")
    public RibbonLoadBalancingHttpClient ribbonLoadBalancingHttpClient(
        IClientConfig config, ServerIntrospector serverIntrospector,
        ILoadBalancer loadBalancer, RetryHandler retryHandler, CloseableHttpClient httpClient) {
        RibbonLoadBalancingHttpClient client = new RibbonLoadBalancingHttpClient(httpClient, config, serverIntrospector);
        client.setLoadBalancer(loadBalancer);
        client.setRetryHandler(retryHandler);
        Monitors.registerObject("Client_" + this.name, client);
        return client;
    }
    
    @Bean
    @ConditionalOnMissingBean(AbstractLoadBalancerAwareClient.class)
    @ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
    public RetryableRibbonLoadBalancingHttpClient retryableRibbonLoadBalancingHttpClient(
            IClientConfig config, ServerIntrospector serverIntrospector,
            ILoadBalancer loadBalancer, RetryHandler retryHandler,
            LoadBalancedRetryFactory loadBalancedRetryFactory, CloseableHttpClient httpClient) {
        RetryableRibbonLoadBalancingHttpClient client = new RetryableRibbonLoadBalancingHttpClient(
            httpClient, config, serverIntrospector, loadBalancedRetryFactory);
        client.setLoadBalancer(loadBalancer);
        client.setRetryHandler(retryHandler);
        Monitors.registerObject("Client_" + this.name, client);
        return client;
    }
}


//自己定义负载均衡的策略
class config{
    @Bean
    public IRule ribbonRule(){
        return new WeightedResponseTimeRule();
    }
}


//调用链
//HystrixInvocationHandler.this.dispatch.get(method).invoke(args);
//SynchronousMethodHandler#invoke
//LoadBalancerFeignClient#execute
//AbstractLoadBalancerAwareClient#executeWithLoadBalancer(S, com.netflix.client.config.IClientConfig)
//LoadBalancerCommand#submit
//LoadBalancerCommand#selectServer

class LoadBalancerCommand{
    private Observable<Server> selectServer() {
        return Observable.create(new OnSubscribe<Server>() {
            @Override
            public void call(Subscriber<? super Server> next) {
                try {
                    //通过负载均衡的算法获取到服务器
                    Server server = loadBalancerContext.getServerFromLoadBalancer(loadBalancerURI, loadBalancerKey);   
                    next.onNext(server);
                    next.onCompleted();
                } catch (Exception e) {
                    next.onError(e);
                }
            }
        });
    }
}

还发现了一个问题: 第一个调用feign接口的时候会在console里面发现
DynamicServerListLoadBalancer for client eurka-client initialized ... 这是为什么?


进行的debug发现: feign里面集成了ribbon, 但是ribbon在项目启动的时候RibbonClientConfiguration并没有进行自动的配置
也就是说只有真正需要使用到ribbon的时候,ribbon才回去初始化(懒加载); 怎么做到的呢? 为什么第一次调用feign接口的时候会去
初始化bean?  

我们对LoadBalancerFeignClient进行了debug 对execute 方法的
IClientConfig requestConfig = getClientConfig(options, clientName);进行断点
这个代码一定是判断应用的上下文里面找不到IClientConfig然后进行bean的自动配置加载, 如果找到了就直接使用;
//getInstance-->getContext 如果发现了context里面没有包含name 那么进行createContext
public abstract class NamedContextFactory<C extends NamedContextFactory.Specification>
		implements DisposableBean, ApplicationContextAware {

	protected AnnotationConfigApplicationContext getContext(String name) {
		if (!this.contexts.containsKey(name)) {
			synchronized (this.contexts) {
				if (!this.contexts.containsKey(name)) {
					this.contexts.put(name, createContext(name));
				}
			}
		}
		return this.contexts.get(name);
	}

    //进行context的创建
	protected AnnotationConfigApplicationContext createContext(String name) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
		if (this.configurations.containsKey(name)) {
			for (Class<?> configuration : this.configurations.get(name)
					.getConfiguration()) {
				context.register(configuration);
			}
		}
		for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
			if (entry.getKey().startsWith("default.")) {
				for (Class<?> configuration : entry.getValue().getConfiguration()) {
					context.register(configuration);
				}
			}
		}
		//defaultConfigType=class org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration
		context.register(PropertyPlaceholderAutoConfiguration.class,
				this.defaultConfigType);
		//propertySourceName=this.propertyName
		context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(
				this.propertySourceName,
				Collections.<String, Object> singletonMap(this.propertyName, name)));
		if (this.parent != null) {
			// Uses Environment from parent as well as beans
			context.setParent(this.parent);
		}
		context.setDisplayName(generateDisplayName(name));
		//context 重新加载一次bean, 新的bean会重新的加载进来
		context.refresh();
		return context;
	}

    //获取实例对象
	public <T> Map<String, T> getInstances(String name, Class<T> type) {
		AnnotationConfigApplicationContext context = getContext(name);
		if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context,
				type).length > 0) {
			return BeanFactoryUtils.beansOfTypeIncludingAncestors(context, type);
		}
		return null;
	}

}

总结

Feign 调用客户端的服务接口就像本地一样的原因就是因为在启动项目的时候, 容器的加载去创建bean的过程中扫描到了
@FeignClient 然后会为改类产生一个jdk的动态代理对象, 代理的内部是调用了hystrix去执行我们的目标方法,
hystrix 一方面有熔断的作用
另外一方面可以在正常的情况下对我们的接口进行调用
SynchronousMethodHandler将我们的请求交给了LoadBalancerFeignClient的execute方法去执行了,
那么在这个过程中间也是需要进过ribbon的负载均衡的;
然后ribbon 将请求的结果交给了代理;返回
如果发现ribbon都没有初始化那么需要刷新refresh context 加载ribbon的自动配置的组件类