Spring Cloud Netflix-OpenFeign基本使用及其原理

本文深入探讨了OpenFeign的基本使用方法及底层实现原理,包括接口定义与注入、FeignClient注解的扫描与解析、代理对象构建过程及远程通信机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


OpenFeign 目标是减少 HTTP API的复杂性,希望能将 HTTP 调用做到像RPC一样易用。OpenFeign的基本原理是将需要调用的接口通过 Spring 中的扩展接口 ImportBeanDefinitionRegistrar 注入成一个 Proxy 对象。

一、OpenFeign基本使用

1.1 OpenFeign接口定义

通过 @FeignClient 注解,定义需要进行 HTTP 通信调用的接口。

@FeignClient("lizq-sys")
public interface IUserService {
    @GetMapping("/user/get")
    UserBean get(@RequestParam Long id);

    @PostMapping("/user/save")
    UserBean save(@RequestBody UserBean userBean);

    @PostMapping("/user/delete")
    void delete(@RequestParam Long id);
}

1.2 OpenFeign接口注入

@Autowired
private IUserService userService;

@GetMapping("/getUser/{id}")
public UserBean getUser(@PathVariable Long id) {
    UserBean user = userService.get(id);
    return user;
}

二、OpenFeign底层原理

在进行 OpenFeign 底层原理分析,首先要指定,OpenFeign 在服务启动过程中,做了什么。

  1. FeignClient 注解的扫描、解析与注入
  2. 接口代理对象的构建
  3. 远程通信的实现

2.1 FeignClient 注解的扫描与解析

OpenFeign 通过 @EnableFeignClients 注解,进行相关初始化。

@EnableFeignClients(basePackages = "com.lizq.netfix")
@SpringBootApplication
public class FinpcApplication {
    public static void main(String[] args) {
        SpringApplication.run(FinpcApplication.class, args);
    }
}

@EnableFeignClients 注解主要是集成了 Spring 中的 @Import 注解,通过 FeignClientsRegistrar 类实现的 ImportBeanDefinitionRegistrar 接口,完成相关初始化动作。

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

FeignClientsRegistrar 的核心方法

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {

	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
		// 注入EnableFeignClients注解中的一些默认配置
        this.registerDefaultConfiguration(metadata, registry);
        // 核心方法:注入所有的 FeignClients 接口对象
        this.registerFeignClients(metadata, registry);
    }
    
    /**
     * 注入所有的 FeignClients 接口对象
     */
    public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
    	/**
    	 * 1.FeignClient 注解的扫描
    	 */
    	// 定义一个存储 BeanDefinition 的集合
		LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();
		
		Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
		AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
		// 获取 EnableFeignClients 注解中的 clients 属性值
		final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");
		if (clients == null || clients.length == 0) {// 如果为空
			// 创建Spring内置的扫描器
			ClassPathScanningCandidateComponentProvider scanner = getScanner();
			scanner.setResourceLoader(this.resourceLoader);
			// 添加过滤器:过滤器所有被 @FeignClient 标记接口
			scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));
			Set<String> basePackages = getBasePackages(metadata);
			for (String basePackage : basePackages) {
				// 获取当前 basePackage 下的所有对象,并封装为 BeanDefinition
				candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
			}
		} else {
			for (Class<?> clazz : clients) {// 如果不为空
				// 将clients 属性值封装为 AnnotatedGenericBeanDefinition对象
				candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz));
			}
		}

		/**
    	 * 2.FeignClient 注解的解析
    	 */
		for (BeanDefinition candidateComponent : candidateComponents) {
			if (candidateComponent instanceof AnnotatedBeanDefinition) {
				// verify annotated class is an interface
				AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
				AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
				Assert.isTrue(annotationMetadata.isInterface(),
						"@FeignClient can only be specified on an interface");

				Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
				
				String name = getClientName(attributes);
				registerClientConfiguration(registry, name, attributes.get("configuration"));
				// 注入FeignClient对象
				registerFeignClient(registry, annotationMetadata, attributes);
			}
		}
	}
	
	/**
	 * 注入FeignClient对象
	 */
	private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
		String className = annotationMetadata.getClassName();
		// 创建一个 BeanDefinitionBuilder 对象,用于构建并注入 FeignClientFactoryBean
		BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
		// 参数校验
		validate(attributes);
		// 设置BeanDefinition参数
		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();
		beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);

		// has a default, won't be null
		boolean primary = (Boolean) attributes.get("primary");

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

2.2 接口代理对象的构建

OpenFeign 接口代理对象的构建,主要是通过 Spring 的扩展接口 FactoryBean<T> 来实现的。在上面的代码中,通过解析 FeignClient 对象,构建成一个 FeignClientFactoryBean 对象,Spring 在注入对应接口是,会调用 FeignClientFactoryBean 对象中的 getObject() 方法,返回注入对应的代理对象。

class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
	@Override
	public Object getObject() throws Exception {
		// 获取目标对象
		return getTarget();
	}
	
	/**
	 * 获取目标对象
	 */
	<T> T getTarget() {
		FeignContext context = applicationContext.getBean(FeignContext.class);
		Feign.Builder builder = feign(context);

		if (!StringUtils.hasText(url)) {// 判断当前 FeignClient 注解中的url是否为空,如果不为空,直接通过url的调用
			if (!name.startsWith("http")) {
				url = "http://" + name;
			}
			else {
				url = name;
			}
			url += cleanPath();
			// 返回目标对象
			return (T) loadBalance(builder, context,
					new HardCodedTarget<>(type, name, url));
		}
		
		if (StringUtils.hasText(url) && !url.startsWith("http")) {
			url = "http://" + url;
		}
		// 构建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();
			}
			if (client instanceof FeignBlockingLoadBalancerClient) {
				// not load balancing because we have a url,
				// but Spring Cloud LoadBalancer is on the classpath, so unwrap
				client = ((FeignBlockingLoadBalancerClient) client).getDelegate();
			}
			builder.client(client);
		}
		Targeter targeter = get(context, Targeter.class);
		// 返回目标对象
		return (T) targeter.target(this, builder, context,
				new HardCodedTarget<>(type, name, url));
	}
}

HystrixTargeter对象

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;
		String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName()
				: factory.getContextId();
		SetterFactory setterFactory = getOptional(name, context, SetterFactory.class);
		if (setterFactory != null) {
			builder.setterFactory(setterFactory);
		}
		Class<?> fallback = factory.getFallback();
		if (fallback != void.class) {
			return targetWithFallback(name, context, target, builder, fallback);
		}
		Class<?> fallbackFactory = factory.getFallbackFactory();
		if (fallbackFactory != void.class) {
			return targetWithFallbackFactory(name, context, target, builder,
					fallbackFactory);
		}

		// 返回目标对象
		return feign.target(target);
	}
}

Feign 对象

public abstract class Feign {
	public <T> T target(Target<T> target) {
		// 创建代理对象
        return this.build().newInstance(target);
    }

	/**
	 * 构建 Feign对象
	 */
    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);
        // 创建代理对象的 InvocationHandler 工厂实例
        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);
    }
}


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

	   // 解析模板:将方法解析,封装为MethodHandler
	   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;
	 }
}

2.3 远程通信的实现

OpenFeign远程通信通过动态代理实现,方法调用就会执行对应的 InvocationHandler 对象中的 Object invoke(final Object proxy, final Method method, final Object[] args) 方法。

final class HystrixInvocationHandler implements InvocationHandler {
  @Override
  public Object invoke(final Object proxy, final Method method, final Object[] args)
      throws Throwable {
    // 是否为 Object 方法,如果为,直接执行
    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();
    }

	// 创建 HystrixCommand 对象,用于进行远程通信:内部会包含以下熔断、降级逻辑
    HystrixCommand<Object> hystrixCommand =
        new HystrixCommand<Object>(setterMethodMap.get(method)) {
          @Override
          protected Object run() throws Exception {
            try {
              // 执行 SynchronousMethodHandler invoke方法
              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 if (isReturnsCompletableFuture(method)) {
                return ((Future) result).get();
              } else {
                return result;
              }
            } catch (IllegalAccessException e) {
              // shouldn't happen as method is public due to being an interface
              throw new AssertionError(e);
            } catch (InvocationTargetException | ExecutionException e) {
              // Exceptions on fallback are tossed by Hystrix
              throw new AssertionError(e.getCause());
            } catch (InterruptedException e) {
              // Exceptions on fallback are tossed by Hystrix
              Thread.currentThread().interrupt();
              throw new AssertionError(e.getCause());
            }
          }
        };

    if (Util.isDefault(method)) {
      return hystrixCommand.execute();
    } else 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();
    } else if (isReturnsCompletableFuture(method)) {
      return new ObservableCompletableFuture<>(hystrixCommand);
    }
    return hystrixCommand.execute();
  }
}
SynchronousMethodHandler 对象
final class SynchronousMethodHandler implements MethodHandler {
	@Override
	public Object invoke(Object[] argv) throws Throwable {
	   // 构建请求的一个模版
	   RequestTemplate template = buildTemplateFromArgs.create(argv);
	   Options options = findOptions(argv);
	   Retryer retryer = this.retryer.clone();
	   while (true) {
	     try {
	       // 执行
	       return executeAndDecode(template, options);
	     } 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, Options options) throws Throwable {
    Request request = targetRequest(template);

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

    Response response;
    long start = System.nanoTime();
    try {
      // 通过 Client执行,进行远程通信
      response = client.execute(request, options);
      // ensure the request is set. TODO: remove in Feign 12
      response = response.toBuilder()
          .request(request)
          .requestTemplate(template)
          .build();
    } 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);


    if (decoder != null)
      return decoder.decode(response, metadata.returnType());

    CompletableFuture<Object> resultFuture = new CompletableFuture<>();
    asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,
        metadata.returnType(),
        elapsedTime);

    try {
      if (!resultFuture.isDone())
        throw new IllegalStateException("Response handling not done");

      return resultFuture.join();
    } catch (CompletionException e) {
      Throwable cause = e.getCause();
      if (cause != null)
        throw cause;
      throw e;
    }
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值