openFeign作为一个http客户端,可以让开发人员像调用一个本地接口一样调用一个http接口,而spring cloud也将openFeign集成到了spring cloud全家桶中,成为了spring cloud体系中微服务接口调用的标准实现,同时spring cloud也扩展的openFeign,使之支持springMVC注解。feign的使用我想大部分人都已经太熟悉了,下面直接进入源码。源码版本:spring-cloud-openfeign-3.1.1
源码入口就是EnableFeignClients这个注解,当开启这个注解,spring就会扫描所有打了FeignClient注解的类,并为之创建动态代理,封装为一个http客户端:
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients
可以看到EnableFeignClients引入了FeignClientsRegistrar这个类,它实现了ImportBeanDefinitionRegistrar,具有注册bean定义的功能:
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//注册默认的feign客户端配置类,所有的feign客户端可以公用这些配置
registerDefaultConfiguration(metadata, registry);
//注册feign客户端
registerFeignClients(metadata, registry);
}
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
LinkedHashSet candidateComponents = new LinkedHashSet<>();
Map attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
final Class>[] clients = attrs == null ? null : (Class>[]) attrs.get("clients");
//注解上的clients属性如果为空,则需要根据扫描的包去扫描带有FeignClient注解的类
if (clients == null || clients.length == 0) {
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));
Set basePackages = getBasePackages(metadata);
for (String basePackage : basePackages) {
candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
}
}
else {
//如果clients属性有值,则直接把指定的clients加入候选者
for (Class> clazz : clients) {
candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz));
}
}
//将每个候选者注册为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 attributes = annotationMetadata
.getAnnotationAttributes(FeignClient.class.getCanonicalName());
String name = getClientName(attributes);
//注册该FeignClient的配置类,其实是注册一个FeignClientSpecification,FeignClient注解上的configuration属性
//将会作为构造器参数传入。注意每个FeignClient都有自己的spring上下文。
registerClientConfiguration(registry, name, attributes.get("configuration"));
//注册FeignClient,其实就是注册一个FactoryBean
registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata,
Map 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
FeignClientFactoryBean factoryBean = new FeignClientFactoryBean();
factoryBean.setBeanFactory(beanFactory);
factoryBean.setName(name);
factoryBean.setContextId(contextId);
factoryBean.setType(clazz);
factoryBean.setRefreshableClient(isClientRefreshEnabled());
//设置bean的instanceSupplier,指定spring bean实例化策略为supplier方式
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));
}
//直接使用了getObject方法拿到真正的bean
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");
//指定为首选bean
beanDefinition.setPrimary(primary);
String[] qualifiers = getQualifiers(attributes);
if (ObjectUtils.isEmpty(qualifiers)) {
qualifiers = new String[] { contextId + "FeignClient" };
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
//注册bean定义
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
//注册可选的Request.Options,可以动态刷新Request配置,貌似不太常用
registerOptionsBeanDefinition(registry, contextId);
}
这里一个最为重要的类:FeignClientFactoryBean,详细看下这个FactoryBean的getObject方法是如何创建feign客户端的:
public Object getObject() {
return getTarget();
}
T getTarget() {
//获取FeignContext,这其实是一个feign的上下文工厂,继承了Spring的NamedContextFactory
//可以为每个feignClient创建一个独立的Spring上下文,FeignContext在FeignAutoConfiguration中自动装配
FeignContext context = beanFactory != null ? beanFactory.getBean(FeignContext.class)
: applicationContext.getBean(FeignContext.class);
//获取一个Feign.Builder
Feign.Builder builder = feign(context);
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();
//创建feign客户端
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));
}
看一下创建Feign.Builder的逻辑,Feign.Builder用来创建一个Feign(ReflectiveFeign)对象,Feign对象用来为我们写的Feign接口创建动态代理:
protected Feign.Builder feign(FeignContext context) {
FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
Logger logger = loggerFactory.create(type);
// @formatter:off
//从feignClient上下文获取Feign.Builder,在FeignClientsConfiguration中自动装配
//如果没有引入断路器或是其它扩展组件,默认就是Feign.Builder
//如果引入了circuitbreaker,则为FeignCircuitBreaker.Builder
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
//根据父容器的客户端配置配置feignClient
//feignClient的配置优先级,默认情况下是
//FeignClientProperties>FeignClientSpecification>自定义配置类>FeignClientsConfiguration
//当然也可以用feign.client.defaultToProperties设置
configureFeign(context, builder);
return builder;
}
然后看loadBalance(builder, context, new HardCodedTarget<>(type, name, url)),在创建feign客户端的时候会加入负载均衡器:
protected T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget target) {
//获取feign客户端,会在Feign.Builder中创建,默认是Client.Default
//可以替换为像ApacheHttpClient等。
//当然这里一般是FeignBlockingLoadBalancerClient,因为引入了spring cloud负载均衡器
//FeignBlockingLoadBalancerClient是对Client.Default的包装,使客户端具有了负载均衡的能力
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
//用FeignBuilderCustomizer配置Feign.Builder,如果有的话
applyBuildCustomizers(context, builder);
//从容器中获取Targeter,默认是DefaultTargeter
//如果引入了断路器,则为FeignCircuitBreakerTargeter,会加入降级的逻辑fallback
Targeter targeter = get(context, Targeter.class);
//创建feign客户端
return targeter.target(this, builder, context, target);
}
throw new IllegalStateException(
"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?");
}
public T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
Target.HardCodedTarget target) {
if (!(feign instanceof FeignCircuitBreaker.Builder)) {
return feign.target(target);
}
//因为引入了断路器,把Feign.Builder强转为FeignCircuitBreaker.Builder
FeignCircuitBreaker.Builder builder = (FeignCircuitBreaker.Builder) feign;
String name = !StringUtils.hasText(factory.getContextId()) ? factory.getName() : factory.getContextId();
//获取降级类或降级工厂
Class> fallback = factory.getFallback();
if (fallback != void.class) {
//以fallback class为例
return targetWithFallback(name, context, target, builder, fallback);
}
Class> fallbackFactory = factory.getFallbackFactory();
if (fallbackFactory != void.class) {
return targetWithFallbackFactory(name, context, target, builder, fallbackFactory);
}
return builder(name, builder).target(target);
}
private T targetWithFallback(String feignClientName, FeignContext context, Target.HardCodedTarget target,
FeignCircuitBreaker.Builder builder, Class> fallback) {
//获取fallback对象
T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type());
//FeignCircuitBreaker.Builder#target
return builder(feignClientName, builder).target(target, fallbackInstance);
}
使用Builder的build方法创建Feign对象:
public Feign build(final FallbackFactory> nullableFallbackFactory) {
//创建Feign对象(ReflectiveFeign)
//设置InvocationHandler工厂为FeignCircuitBreakerInvocationHandler
super.invocationHandlerFactory((target, dispatch) -> new FeignCircuitBreakerInvocationHandler(
circuitBreakerFactory, feignClientName, target, dispatch, nullableFallbackFactory,
circuitBreakerGroupEnabled, circuitBreakerNameResolver));
//调用父类创建ReflectiveFeign
return super.build();
}
下面看一下创建ReflectiveFeign逻辑,ReflectiveFeign用来创建动态代理:
public Feign build() {
//在FeignClientFactoryBean#configureFeign中会把容器中的Capability设置进来
//Capability对象可以增强Feign的各个组件,一般就是对原有的组件的包装
Client client = Capability.enrich(this.client, capabilities);
Retryer retryer = Capability.enrich(this.retryer, capabilities);
List requestInterceptors = this.requestInterceptors.stream()
.map(ri -> Capability.enrich(ri, capabilities))
.collect(Collectors.toList());
Logger logger = Capability.enrich(this.logger, capabilities);
Contract contract = Capability.enrich(this.contract, capabilities);
Options options = Capability.enrich(this.options, capabilities);
Encoder encoder = Capability.enrich(this.encoder, capabilities);
Decoder decoder = Capability.enrich(this.decoder, capabilities);
InvocationHandlerFactory invocationHandlerFactory =
Capability.enrich(this.invocationHandlerFactory, capabilities);
QueryMapEncoder queryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities);
//SynchronousMethodHandler.Factory,用来创建MethodHandler的工厂
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404, closeAfterDecode, propagationPolicy, forceDecoding);
//ParseHandlersByName,用来创建方法名与对应MethodHandler的映射关系
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
}
Feign#newInstance创建feign接口的动态代理:
public T newInstance(Target target) {
//这里的target为HardCodedTarget,包含了该feign客户端的接口类型,name,url
//用ParseHandlersByName创建方法名和MethodHandler的映射map
Map nameToHandler = targetToHandlersByName.apply(target);
//Method对象和MethodHandler的映射map
Map methodToHandler = new LinkedHashMap();
List defaultMethodHandlers = new LinkedList();
//遍历接口的每个方法
for (Method method : target.type().getMethods()) {
if (method.getDeclaringClass() == Object.class) {
continue;
} else if (Util.isDefault(method)) {
//如果是default方法,则用DefaultMethodHandler处理,这种方法会使用java7的MethodHandle调用
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)));
}
}
//jdk动态代理的InvocationHandler,这里为FeignCircuitBreakerInvocationHandler
InvocationHandler handler = factory.create(target, methodToHandler);
//创建动态代理
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
new Class>[] {target.type()}, handler);
for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
//将MethodHandle绑定到代理对象
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
动态代理这下就创建完了,接下来是feign接口的调用过程。
未完待续。。。