1、OpenFeign概述
OpenFeign 组件的前身是 Netflix Feign 项目,由 Netflix 公司开发。后来 Feign 项目被贡献给了开源组织,随后Feign退出历史舞台。
OpenFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类
。实现类中OpenFeign 提供了一种声明式的远程调用接口,它可以大幅简化远程调用的编程体验。
2、OpenFeign的动态代理(JDK的动态代理)
OpenFeing 通过 Java 动态代理生成了一个“代理类”,这个代理类将接口调用转化成为了一个远程服务调用。
SpringCloud的服务调用方中
-
在项目启动阶段,OpenFeign 框架会发起一个主动的扫包流程,从指定的目录下扫描并加载所有被 @FeignClient 注解修饰的接口。
-
OpenFeign 会针对每一个 FeignClient 接口生成一个动态代理对象
-
动态代理对象会被添加到 Spring 上下文中,并注入到对应的服务里
-
发起底层方法调用
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
private ResourceLoader resourceLoader;
private Environment environment;
FeignClientsRegistrar() {
}
//...省略
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
/**
* ImportBeanDefinitionRegistrar以Spring钩子函数的方式自定义Definitions
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// 注册默认的Feign配置
registerDefaultConfiguration(metadata, registry);
// 注册所有定义的FeignClient
registerFeignClients(metadata, registry);
}
private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
Map<String, Object> defaultAttrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
String name;
if (metadata.hasEnclosingClass()) {
name = "default." + metadata.getEnclosingClassName();
}
else {
name = "default." + metadata.getClassName();
}
registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration"));
}
}
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();
Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");
if (clients == null || clients.length == 0) {
// 扫描被FeignClient注解修饰的类
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));
Set<String> basePackages = getBasePackages(metadata);
for (String basePackage : basePackages) {
// 扫描BeanDefinition
candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
}
}
else {
for (Class<?> clazz : clients) {
candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz));
}
}
// 封装为BeanDefinition注册进Spring容器中
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"));
registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata,
Map<String, Object> attributes) {
String className = annotationMetadata.getClassName();
Class clazz = ClassUtils.resolveClassName(className, null);
ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory
? (ConfigurableBeanFactory) registry : null;
String contextId = getContextId(beanFactory, attributes);
String name = getName(attributes);
// 触发动态代理的构造过程。
FeignClientFactoryBean factoryBean = new FeignClientFactoryBean();
factoryBean.setBeanFactory(beanFactory);
factoryBean.setName(name);
factoryBean.setContextId(contextId);
factoryBean.setType(clazz);
factoryBean.setRefreshableClient(isClientRefreshEnabled());
// 动态创建bean
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> {
factoryBean.setUrl(getUrl(beanFactory, attributes));
factoryBean.setPath(getPath(beanFactory, attributes));
factoryBean.setDecode404(Boolean.parseBoolean(String.valueOf(attributes.get("decode404"))));
Object fallback = attributes.get("fallback");
if (fallback != null) {
factoryBean.setFallback(fallback instanceof Class ? (Class<?>) fallback
: ClassUtils.resolveClassName(fallback.toString(), null));
}
Object fallbackFactory = attributes.get("fallbackFactory");
if (fallbackFactory != null) {
factoryBean.setFallbackFactory(fallbackFactory instanceof Class ? (Class<?>) fallbackFactory
: ClassUtils.resolveClassName(fallbackFactory.toString(), null));
}
// 负载均衡及动态代理FeignClientFactoryBean.getObject()
return factoryBean.getObject();
});
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
definition.setLazyInit(true);
validate(attributes);
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
beanDefinition.setAttribute("feignClientsRegistrarFactoryBean", factoryBean);
// has a default, won't be null
boolean primary = (Boolean) attributes.get("primary");
beanDefinition.setPrimary(primary);
String[] qualifiers = getQualifiers(attributes);
if (ObjectUtils.isEmpty(qualifiers)) {
qualifiers = new String[] { contextId + "FeignClient" };
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
registerOptionsBeanDefinition(registry, contextId);
}
//...省略
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
// 定义了一个BeanDefinition
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(configuration);
// 将BeanDefinition注册到BeanFactory中
registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),
builder.getBeanDefinition());
}
/**
* 读取配置文件
*/
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
//...省略
}
public class FeignClientFactoryBean
implements FactoryBean<Object>, InitializingBean, ApplicationContextAware, BeanFactoryAware {
//...省略
/**
* 创建负载均衡的client
*/
protected <T> T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget<T> target) {
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
applyBuildCustomizers(context, builder);
Targeter targeter = get(context, Targeter.class);
// 创建动态代理对象
return targeter.target(this, builder, context, target);
}
// 如果使用openFeign 未引用spring-cloud-starter-loadbalancer包就会抛出异常
throw new IllegalStateException(
"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?");
}
//...省略
@Override
public Object getObject() {
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() {
// FeignClient是Client的动态代理对象,而Client对象是真正执行http请求的对象
// 获取Feign的上下文
FeignContext context = beanFactory != null ? beanFactory.getBean(FeignContext.class)
: applicationContext.getBean(FeignContext.class);
Feign.Builder builder = feign(context);
// 如果url没有定义,则进入到该判断中创建对象,该判断中创建的对象具有负载均衡功能
// @FeignClient(value = "lyy-cloud-server", path = "/user",url = "192.168.0.105") 如果配置url就不会创建负载均衡了
if (!StringUtils.hasText(url)) {
if (LOG.isInfoEnabled()) {
LOG.info("For '" + name + "' URL not provided. Will try picking an instance via load-balancing.");
}
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;
}
String url = this.url + cleanPath();
Client client = getOptional(context, Client.class);
if (client != null) {
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();
}
if (client instanceof RetryableFeignBlockingLoadBalancerClient) {
// not load balancing because we have a url,
// but Spring Cloud LoadBalancer is on the classpath, so unwrap
client = ((RetryableFeignBlockingLoadBalancerClient) client).getDelegate();
}
builder.client(client);
}
applyBuildCustomizers(context, builder);
Targeter targeter = get(context, Targeter.class);
// 创建动态代理对象
return (T) targeter.target(this, builder, context, new HardCodedTarget<>(type, name, url));
}
//...省略
}
// 创建动态代理对象
targeter.target()→DefaultTargeter.target()→Feign.Builder.target()→Feign.newInstance()→
ReflectiveFeign.newInstance()。
public class ReflectiveFeign extends Feign {
private final ReflectiveFeign.ParseHandlersByName targetToHandlersByName;
private final InvocationHandlerFactory factory;
private final QueryMapEncoder queryMapEncoder;
ReflectiveFeign(ReflectiveFeign.ParseHandlersByName targetToHandlersByName, InvocationHandlerFactory factory, QueryMapEncoder queryMapEncoder) {
this.targetToHandlersByName = targetToHandlersByName;
this.factory = factory;
this.queryMapEncoder = queryMapEncoder;
}
public <T> T newInstance(Target<T> target) {
// nameToHandler 主要用于处理用户自定义的方法
Map<String, MethodHandler> nameToHandler = this.targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap();
// DefaultMethodHandler用于处理接口中default方法
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList();
Method[] var5 = target.type().getMethods();
int var6 = var5.length;
// 遍历接口中的所有方法
for(int var7 = 0; var7 < var6; ++var7) {
// 定义的方法
Method method = var5[var7];
// 跳过Object中的方法
if (method.getDeclaringClass() != Object.class) {
// 如果是default方法,则创建DefaultMethodHandler处理
if (Util.isDefault(method)) {
DefaultMethodHandler handler = new DefaultMethodHandler(method);
defaultMethodHandlers.add(handler);
methodToHandler.put(method, handler);
} else {
// 用户自定义的方法,此时从nameToHandler中拿出SynchronousMethodHandler进行映射
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
}
// 创建InvocationHandler 核心代理对象,代理逻辑都封装在该对象中。
// 注意,这里传递了methodToHandler(method→MethodHandler)这个映射,
// MethodHandler可能是DefaultMethodHandler(处理default方法)或者SynchronousMethodHandler(处理用户定义的远程调用方法)。
// 代理过程中,会根据方法名称dispatch到这个映射中对应的MethodHandler进行处理。
InvocationHandler handler = this.factory.create(target, methodToHandler);
// 创建代理对象
T proxy = Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, handler);
Iterator var12 = defaultMethodHandlers.iterator();
while(var12.hasNext()) {
DefaultMethodHandler defaultMethodHandler = (DefaultMethodHandler)var12.next();
defaultMethodHandler.bindTo(proxy);
}
// 返回代理对象
return proxy;
}
//...省略
}
this.factory.create→InvocationHandlerFactory→Default.create→FeignInvocationHandler
调用方调用服务提供方方法会调用FeignInvocationHandler.invoke是用户定义的远程调用方法,则从dispatch映射中获取对应的SynchronousMethodHandler.invoke()处理
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = this.buildTemplateFromArgs.create(argv);
Options options = this.findOptions(argv);
Retryer retryer = this.retryer.clone();
while(true) {
try {
// 具体执行远程调用的方法
return this.executeAndDecode(template, options);
} catch (RetryableException var9) {
RetryableException e = var9;
try {
// 判断是否需要重试
retryer.continueOrPropagate(e);
} catch (RetryableException var8) {
Throwable cause = var8.getCause();
if (this.propagationPolicy == ExceptionPropagationPolicy.UNWRAP && cause != null) {
throw cause;
}
throw var8;
}
if (this.logLevel != Level.NONE) {
this.logger.logRetry(this.metadata.configKey(), this.logLevel);
}
}
}
}
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
// 构造请求对象
Request request = this.targetRequest(template);
if (this.logLevel != Level.NONE) {
this.logger.logRequest(this.metadata.configKey(), this.logLevel, request);
}
long start = System.nanoTime();
Response response;
try {
// 执行http请求,引用spring-cloud-loadbalancer后this.client为FeignBlockingLoadBalancerClient
response = this.client.execute(request, options);
response = response.toBuilder().request(request).requestTemplate(template).build();
} catch (IOException var12) {
if (this.logLevel != Level.NONE) {
this.logger.logIOException(this.metadata.configKey(), this.logLevel, var12, this.elapsedTime(start));
}
throw FeignException.errorExecuting(request, var12);
}
//...省略
}