文章目录
一、注册FeignClient配置类和FeignClient BeanDefinition
1.@EnableFeignClients注解
先来看一下启动类上@EnableFeignClients注解,跟进直接看下都做了些什么:
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
ResourceLoaderAware, EnvironmentAware {
// patterned after Spring Integration IntegrationComponentScanRegistrar
// and RibbonClientsConfigurationRegistgrar
private ResourceLoader resourceLoader;
private Environment environment;
public FeignClientsRegistrar() {
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//注册默认配置
registerDefaultConfiguration(metadata, registry);
//注册所有FeignClent beanDeifintion
registerFeignClients(metadata, registry);
}
2.注册bean配置的两个方法
分别来看一下上面两个方法:注册默认配置方法registerDefaultConfiguration
private void registerDefaultConfiguration(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//获取EnableFeignClients注解里面所有属性key和value
Map<String, Object> defaultAttrs = metadata
.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
String name;
//判断是否存在内部类,例如default.xxx.TestApplication
if (metadata.hasEnclosingClass()) {
//针对注解元数据metadate对应一个内部类或者方法返回的方法本地类的情形
name = "default." + metadata.getEnclosingClassName();
}
else {
name = "default." + metadata.getClassName();
}
//name 默认以default开头,之后会根据名称选择配置
registerClientConfiguration(registry, name,
defaultAttrs.get("defaultConfiguration"));
}
}
registerDefaultConfiguration方法是读取启动类上面@EnableFeignClients注解中声明Feign相关配置类,默认name为Default,一般情况下不无需配置。用默认的feignAutoConfiguration即可。有一个比较重要的方法:注册配置registerClientConfiguration,启动流程中一共有两处读取了feign配置类,这里是第一处,先来看一下方法:
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
Object configuration) {
//定义FeignClientSpecification的Definition构建器
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientSpecification.class);
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(configuration);
//注册bean,(会存在多个FeignClientSpecification但key不同)
registry.registerBeanDefinition(
name + "." + FeignClientSpecification.class.getSimpleName(),
builder.getBeanDefinition());
}
将bean配置类包装成FeignClientSpecification,注入到容器中。这个对象非常重要,其中包含了FeignClient需要的重试策略、超时策略、日志等配置,如果某个服务没有配置,则读取默认配置。扫描FeignClient registerFeignClients方法主要扫描类路径,对所有的FeignClient生成对应的BeanDefinItion
public void registerFeignClients(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
//初始化扫描器
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
Set<String> basePackages;
//获取EnableFeignClients注解里面的所有属性key和Value
Map<String, Object> attrs = metadata
.getAnnotationAttributes(EnableFeignClients.class.getName());
//定义扫描器的过滤规则(只获取FeignClient注解修饰的类)
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
FeignClient.class);
final Class<?>[] clients = attrs == null ? null
: (Class<?>[]) attrs.get("clients");
//是否制定clients属性
if (clients == null || clients.length == 0) {
scanner.addIncludeFilter(annotationTypeFilter);
basePackages = getBasePackages(metadata);
}
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)));
}
//获取扫描目录下面所有的bean BeanDefinition
for (String basePackage : basePackages) {
Set<BeanDefinition> candidateComponents = scanner
.findCandidateComponents(basePackage);
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition) {