Feign原理_feign基于什么协议

2022-11-10 14:31:03 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

一、feign测试代码

1.服务接口上标注@FeignClient

代码语言:javascript复制
@FeignClient("order")
public interface OrderServiceFeign { 
   
    @GetMapping("/getOrder")
    String getOrder();
}

2.调用方可以直接注入然后直接调用访问

代码语言:javascript复制
@RestController
@RequestMapping("/feign")
public class FeignTestController { 
   

    @Autowired
    private OrderServiceFeign orderServiceFeign;
    
    @GetMapping("/order")
    public String getOrder() { 
   
        return orderServiceFeign.getOrder();
    }
}

3.在调用方的启动类上加上一个启动注解@EnableFeignClients

代码语言:javascript复制
@SpringBootApplication
@EnableFeignClients
public class UserServiceApplication { 
   
    public static void main(String[] args) { 
   
        SpringApplication.run(UserServiceApplication.class, args);
    }
}
二、寻找入口

springcloud组件基本都是启动的注解,也就是@EnableFeignClients

1.@EnableFeignClients干了什么?
代码语言:javascript复制
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients { 

我们看到Import注解里面有个FeignClientsRegistrar类,在spring中看到以Registrar结尾的类,就会想到spring的bean的动态装备,一个是selecter,一个是registrar.

简单介绍下registrar 比如我们要将类RegistrarBean 装在的spring 装载到spring容器

代码语言:javascript复制
public class RegistrarBean { 
   
}

定义一个类实现ImportBeanDefinitionRegistrar 接口,实现registerBeanDefinitions方法,然后通过registry的registerBeanDefinition可以注册一个实例到spring当中

代码语言:javascript复制
public class SpringRegistrarTest implements ImportBeanDefinitionRegistrar { 
   
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 
   
        BeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClassName(RegistrarBean.class.getName());
        registry.registerBeanDefinition("registrarBean",beanDefinition);
    }
}

定义一个自定义注解,用Import注解导入我们上面写的SpringRegistrarTest 类

代码语言:javascript复制
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(SpringRegistrarTest.class)
public @interface EnableRegistrar { 
   
}

将我们写的注解配置到启动类上

代码语言:javascript复制
@SpringBootApplication
@EnableFeignClients
@EnableRegistrar
public class UserServiceApplication { 
   

    public static void main(String[] args) { 
   
        ConfigurableApplicationContext applicationContext = SpringApplication.run(UserServiceApplication.class, args);
        Object registrarBean = applicationContext.getBean("registrarBean");
        System.out.println(registrarBean);
    }
}

我们在返回的context对象去获取我们去注册的bean,是可以拿到的

我们接着看FeignClientsRegistrar这个类

代码语言:javascript复制
public void registerBeanDefinitions(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) { 
   
		// 注册默认的配置类
		registerDefaultConfiguration(metadata, registry);
		// 注册feign客户端
		registerFeignClients(metadata, registry);
	}

我们看registerFeignClients里面有这样几行代码

代码语言:javascript复制
		BeanDefinitionBuilder definition = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);
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);

我们发现注册了一个FeignClientFactoryBean的类,它实现了FactoryBean,它提供了一个getObject方法,当我们依赖注入一个feign客户端对象的时候,这个方法就会被调用

代码语言:javascript复制
public Object getObject() throws Exception { 

// 获取FeignContext 对象
FeignContext context = applicationContext.getBean(FeignContext.class);
// 构建一个Feign.Builder 对象
Feign.Builder builder = feign(context);
if (!StringUtils.hasText(this.url)) { 

String url;
if (!this.name.startsWith("http")) { 

url = "http://"   this.name;
}
else { 

url = this.name;
}
url  = cleanPath();
return loadBalance(builder, context, new HardCodedTarget<>(this.type,
this.name, 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) { 

client = ((LoadBalancerFeignClient)client).getDelegate();
}
builder.client(client);
}
Targeter targeter = get(context, Targeter.class);
return targeter.target(this, builder, context, new HardCodedTarget<>(
this.type, this.name, url));
}

1.获取FeignContext 对象,FeignContext 是怎么来的? 有一个自动装配类FeignAutoConfiguration,创建了这个对象 FeignAutoConfiguration类

代码语言:javascript复制
@Bean
public FeignContext feignContext() { 

FeignContext context = new FeignContext();
context.setConfigurations(this.configurations);
return context;
}

而且我们发现创建FeignContext中还调用了父类的构造器,传入了一个FeignClientsConfigurationfegin会根据不同的服务创建不同的spring上下文,在创建不同的应用上下文时,这个类会被加载到上下文当中

FeignContext类

代码语言:javascript复制
	public FeignContext() { 

super(FeignClientsConfiguration.class, "feign", "feign.client.name");
}

FeignClientsConfiguration类 这个类创建了Decoder ,Encoder 对象,对数据进行编解码,相当于序列化和反序列化。有一个Contract对象, 这个对象是用的SpringMvcContract对象,这个对象是用来解析请求的一个模板的,不如请求方式,路径,参数等。 还有 Feign.Builder,日志工厂等对象。

代码语言:javascript复制
@Configuration
public class FeignClientsConfiguration { 

@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Autowired(required = false)
private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>();
@Autowired(required = false)
private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>();
@Autowired(required = false)
private Logger logger;
@Bean
@ConditionalOnMissingBean
public Decoder feignDecoder() { 

return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
}
@Bean
@ConditionalOnMissingBean
public Encoder feignEncoder() { 

return new SpringEncoder(this.messageConverters);
}
@Bean
@ConditionalOnMissingBean
public Contract feignContract(ConversionService feignConversionService) { 

return new SpringMvcContract(this.parameterProcessors, feignConversionService);
}
@Bean
public FormattingConversionService feignConversionService() { 

FormattingConversionService conversionService = new DefaultFormattingConversionService();
for (FeignFormatterRegistrar feignFormatterRegistrar : feignFormatterRegistrars) { 

feignFormatterRegistrar.registerFormatters(conversionService);
}
return conversionService;
}
@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();
}
}
@Bean
@ConditionalOnMissingBean
public Retryer feignRetryer() { 

return Retryer.NEVER_RETRY;
}
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
public Feign.Builder feignBuilder(Retryer retryer) { 

return Feign.builder().retryer(retryer);
}
@Bean
@ConditionalOnMissingBean(FeignLoggerFactory.class)
public FeignLoggerFactory feignLoggerFactory() { 

return new DefaultFeignLoggerFactory(logger);
}

2.构建一个Feign.Builder对象

代码语言:javascript复制
protected Feign.Builder feign(FeignContext context) { 

FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
Logger logger = loggerFactory.create(this.type);
// @formatter:off
Feign.Builder builder = get(context, Feign.Builder.class)
// required values
.logger(logger)
.encoder(get(context, Encoder.class))
.decoder(get(context, Decoder.class))
.contract(get(context, Contract.class));
// @formatter:on
configureFeign(context, builder);
return builder;
}

在上下文当中去获取Feign.Builder,并设置编码,解码器,模板解析,日志等,这些对象都是在FeignClientsConfiguration 这个类中创建的。

代码语言:javascript复制
	protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
HardCodedTarget<T> target) { 

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

在loadBalance方法中,又在builder,设置了一个client 对象,这个对象是LoadBalancerFeignClient的这么一个对象,他在是FeignRibbonClientAutoConfiguration这个自动装备类,有个Import注解的内容加载了一个DefaultFeignLoadBalancedConfiguration对象,里面有如下代码

代码语言:javascript复制
@Configuration
class DefaultFeignLoadBalancedConfiguration { 

@Bean
@ConditionalOnMissingBean
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory) { 

return new LoadBalancerFeignClient(new Client.Default(null, null),
cachingFactory, clientFactory);
}
}

feign类

代码语言:javascript复制
  public <T> T target(Target<T> target) { 

return build().newInstance(target);
}

build返回了一个ReflectiveFeign对象

代码语言:javascript复制
    public Feign build() { 

SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404);
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder,
errorDecoder, synchronousMethodHandlerFactory);
return new ReflectiveFeign(handlersByName, invocationHandlerFactory);
}

ReflectiveFeign类 可以看到返回一个代理对象

代码语言:javascript复制
  public <T> T newInstance(Target<T> target) { 

// 通过contract 将一个个方法解析成MethodHandler对象。实际上是SynchronousMethodHandler
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;
}
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);
}

通过contract 将一个个方法解析成MethodHandler对象。实际上是SynchronousMethodHandler。 当请求过来后会进入到FeignInvocationHandlerinvoke方法,最后获取相应的MethodHandler去执行

流程图

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/188893.html原文链接:https://javaforall.cn

0 人点赞