一.源码入口
1. 开启Feign客户端的核心注解为:@EnableFeignClients,表示该项目能够被声明为Feign的客户端
@Slf4j
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClientspublic class NnDataApplication {
public static void main(String[] args) throws UnknownHostException {
ConfigurableApplicationContext application = SpringApplication.run(NnDataApplication.class, args);
}
2.@EnableFeignClients中的核心类是 FeignClientsRegistrar ,可以看到核心方法 registerBeanDefinitions()
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//2.1 注册Feign相关的配置
registerDefaultConfiguration(metadata, registry);
//2.2 注册FeignClient对象
registerFeignClients(metadata, registry);
}
2.1.将FeignClients的默认的配置属性封装成 FeignClientSpecification 的BeanDifinition对象
private void registerDefaultConfiguration(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//解析EnableFeignClients注解中的defaultAttrs默认属性,封装成Map
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();
}
//注册FeignClientSpecification 的 BeanDifinition对象
registerClientConfiguration(registry, name,
defaultAttrs.get("defaultConfiguration"));
}
}
2.2.解析指定路径(或默认路径下的)@FeignClient注解的属性和接口,将FeignClient对象封装成 FeignClientFactoryBean类的BeanDifinition对象,核心方法
public void registerFeignClients(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//获取类路径扫描器,作用是:扫描指定路径或者默认路径下的被@FeignClient注解修饰的接口以及@FeignClient中的属性
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
//定义包扫描路径
Set<String> basePackages;
//从@EnableFeignClient注解上获取所有的属性,封装成Map
Map<String, Object> attrs = metadata
.getAnnotationAttributes(EnableFeignClients.class.getName());
//注解过滤器,作用是,在扫描路径下 过滤出被@FeignClient修饰的接口
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
FeignClient.class);
//解析@EnableFeignClient中的clients属性(client属性主要是指定被@FeignClient修饰的类,指定该属性会覆盖包扫描路径下的被@FeignClient修饰的类)
final Class<?>[] clients = attrs == null ? null
: (Class<?>[]) attrs.get("clients");
//指定了clients属性
if (clients == null || clients.length == 0) {
scanner.addIncludeFilter(annotationTypeFilter);
//从Map中 ,获取包路径
basePackages = getBasePackages(metadata);
}
//没有指定clients属性
else {
final Set<String> clientClasses = new HashSet<>();
basePackages = new HashSet<>();
for (Class<?> clazz : clients) {
basePackages.add(ClassUtils.getPackageName(clazz));
clientClasses.add(clazz.getCanonicalName());
}
AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
@Override
protected boolean match(ClassMetadata metadata) {
String cleaned = metadata.getClassName().replaceAll("\$", ".");
return clientClasses.contains(cleaned);
}
};
//将注解类型过滤器,塞到包路径扫描器中
scanner.addIncludeFilter(
new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
}
//遍历处理好的包路径集合 basePackages
for (String basePackage : basePackages) {
Set<BeanDefinition> candidateComponents = scanner
.findCandidateComponents(basePackage);
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition) {
// verify annotated class is an interface 校验被@FeignClient修饰的类是否是接口
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());
//从属性中获取Client的名称
String name = getClientName(attributes);
//注册FeignClient中的配置信息,将配置信息注册为FeignClientSpecification 类型的BeanDifinition对象,参考2.1
registerClientConfiguration(registry, name,
attributes.get("configuration"));
//将 1.BeanDifinition注册器,2.包路径的元数据信息,3.@FeignClient中的属性的信息 通过registerFeignClient()方法注册为 FeignClientFactoryBean类的BeanDifinition对象
registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
}
2.2.1.注册FeignClientFactoryBean的BD对象
private void registerFeignClient(BeanDefinitionRegistry registry,
AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
//获取类名
String className = annotationMetadata.getClassName();
//构建 FeignClientFactoryBean对象,该对象实现了 Spring框架中的FactoryBean对象,在实例化时会调用getObject()方法将相关的对象注册到Spring容器中
BeanDefinitionBuilder definition = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);
validate(attributes);
//将@FeignClient上的属性封装到BD对象中
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();
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);
}