文章目录
Openfeign源码浅析
Openfeign用途
- Openfeing是一个声明式的一个http客户端,我们只需要在接口上加个@FeignClient注解就可以用于发起http请求。
Openfeign特性
- 能够结合注册中心通过service服务发现负责均衡的方式发起调用,也能够指定url直接发起调用(如果url是个k8s的svc服务地址k8s会自动负载均衡)
- 配置能够支持contextId维度隔离(可理解为接口维度),也就是说可以在服务接口维度支持请求超时时间、重试次数、编解码配置、日志级别等隔离,通过NamedContextFactory来实现
- 能够方法与第三方的高可用件实现请求限流、熔断、降级等,比如与Hystrix、resilience4j、sentinel
Openfeign组件
- Client:发送http请求的客户端
- Default:默认实现,用于指定url时使用
- FeignBlockingLoadBalancerClient:用于结合注册中心负载均衡时使用
- RetryableFeignBlockingLoadBalancerClient:支持重试,用于结合注册中心负载均衡时使用
- OkHttpClient:需要引入feign-okhttp依赖
- Targeter:目标接口,用于支持熔断扩展实现
- DefaultTargeter:默认实现
- FeignCircuitBreakerTargeter:支持熔断,需要通过spring.cloud.openfeign.circuitbreaker.enabled开启,并且引入熔断组件,比如:spring-cloud-starter-circuitbreaker-resilience4j
- Contract:用于解析接口上的方法,解析为方法对应MethodMetadata列表[]
- MethodMetadata:方法的元数据,包含returnType、bodyType、RequestTemplate
- RequestTemplate:@RequestMapping解析的封装在这,最终会转换为Request(url、method、header、body)
- MethodHandler:每个接口的方法对应的处理器,包含方法的MethodMetadata、目标对象、client
- SynchronousMethodHandler:
- AsynchronousMethodHandler:
- FeignInvocationHandler:每个方法执行的代理方法,jdk动态代理实现的
- Map<Method, MethodHandler> dispatch维护了方法和对应的方法处理器
- Encoder:对象转字节数组,一般是通过Content-Type和HttpMessageConverter来进行编码
- SpringEncoder
- SpringFormEncoder
- Decoder:字节数组转对象,一般是通过Content-Type和HttpMessageConverter来进行解码
代理生成流程
- org.springframework.cloud.openfeign.FeignClientFactoryBean#getObject
- org.springframework.cloud.openfeign.DefaultTargeter#target
- feign.Feign.Builder#target(feign.Target)
- feign.ReflectiveFeign#newInstance
- feign.ReflectiveFeign.ParseHandlersByName#apply
- feign.Contract#parseAndValidateMetadata
- feign.InvocationHandlerFactory#create
- FeignInvocationHandler:包含一个Map<Method, MethodHandler> methodToHandler和
源码执行流程
- FeignAutoConfiguration-》openFeign的自动配置
- EnableFeignClients-》@Import(FeignClientsRegistrar.class)
- FeignClientsRegistrar.class -》是个ImportBeanDefinitionRegistrar实现,扫描FeignClient注解的接口
- FeignClientFactoryBean-》BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
- 接着看FeignClientFactoryBean.getObject
- getTarget(); 生成目标对象
- feign(feignClientFactory);构建feign
- ReflectiveFeign-》
- FeignInvocationHandler-》
FeignClient代理生成流程
- feign.ReflectiveFeign#newInstance
- 通过contract组件把接口上方法解析为方法元数据列表List
- 再把List转换为Map<String, MethodHandler>nameToHandler映射,key为接口名+方法名+参数类型,value:一般为SynchronousMethodHandler
- 在把nameToHandler映射转换为Map<Method, MethodHandler> methodToHandler方法 和方法处理器的映射,为后面执行的时候根据方法找到MethodHandler
- 在根据methodToHandler创建jdk的动态代理调用处理器 FeignInvocationHandler
java
复制代码
public <T> T newInstance(Target<T> target) {
//通过contract组件把接口上方法解析为方法元数据列表List<MethodMetadata>,并转换为Map<String, MethodHandler>nameToHandler
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
//在把nameToHandler映射转换为Map<Method, MethodHandler> methodToHandler方法 和方法处理器的映射
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)));
}
}
//根据methodToHandler创建jdk的动态代理调用处理器 FeignInvocationHandler
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;
}
FeignClient接口代理执行流程
- feign.ReflectiveFeign.FeignInvocationHandler#invoke
- 通过methodToHandler根据方法找到MethodHandler
- 执行MethodHandler的调用,feign.SynchronousMethodHandler#invoke
- feign.SynchronousMethodHandler#invoke
java
复制代码
public Object invoke(Object[] argv) throws Throwable {
//编码:通过Encoder组件把方法上的参数编码,与springmvc一致也是通过HttpMessageConverter来进行编码,messageConverter.write
RequestTemplate template = buildTemplateFromArgs.create(argv);
Options options = findOptions(argv);
Retryer retryer = this.retryer.clone();
while (true) {
try {
//执行调用并把响应解码为我们定义的方法返回值
return executeAndDecode(template, options);
} catch (RetryableException e) {
//重试
retryer.continueOrPropagate(e);
continue;
}
}
}
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
Request request = targetRequest(template);
Response response;
try {
//通过client组件发起http请求
response = client.execute(request, options);
response = response.toBuilder()
.request(request)
.requestTemplate(template)
.build();
} catch (IOException e) {
}
if (decoder != null)
//通过decoder把响应数据解码我们的对象,即:messageConverter.read
return decoder.decode(response, metadata.returnType());
}
Openfeign实现
从FeignClient注解开始
- 我们只在接口上加个@FeignClient注解就能够发起http请求,那么根据以往的经验应该是把FactoryBean注入到spring容器,然后在调用FactoryBean.getObject方法的时候返回一个代理实例。
- 顺着@FeignClient我们找到是FeignClientsRegistrar(ImportBeanDefinitionRegistrar实现)把含有@FeignClient的接口注册到spring容器,那么我们看看他代码实现
java
复制代码
//org.springframework.cloud.openfeign.FeignClientsRegistrar#registerBeanDefinitions
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//注册默认的配置
registerDefaultConfiguration(metadata, registry);
//注册FeignClient
registerFeignClients(metadata, registry);
}
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) {
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
//扫描包含FeignClient的类
scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));
Set<String> basePackages = getBasePackages(metadata);
for (String basePackage : basePackages) {
candidateComponents.addAll(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注解上的属性值
Map<String, Object> attributes = annotationMetadata
.getAnnotationAttributes(FeignClient.class.getCanonicalName());
String name = getClientName(attributes);
//注册注解configuration的配置
registerClientConfiguration(registry, name, attributes.get("configuration"));
//我们继续关注FeignClient注册
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
FeignClientFactoryBean factoryBean = new FeignClientFactoryBean();
factoryBean.setBeanFactory(beanFactory);
factoryBean.setName(name);
factoryBean.setContextId(contextId);
factoryBean.setType(clazz);
factoryBean.setRefreshableClient(isClientRefreshEnabled());
//把注解属性上的值赋值到FeignClientFactoryBean
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");
Object fallbackFactory = attributes.get("fallbackFactory");
return factoryBean.getObject();
});
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
画图总结