这是一篇基于Spring openfeign,关于Spring的一些常用组件,类,编写方式的笔记与源码阅读。
Spring openfeign封装了openfeign,这里暂时不讨论关于openfeign的详细实现,主要考虑
Spring通过什么方法将openfeign注入的。
Spring使用openfeign通过注解@EnableFeignClients,EnableFeignClients使用Import注解
,包含一个ImportBeanDefinitionRegistrar的实现类FeignClientsRegistrar。这里出现了
第一个关键接口ImportBeanDefinitionRegistrar,可以使用Import导入配置。
我们关注它的实现方法registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry),如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { registerDefaultConfiguration(metadata, registry); // 调用方法 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); scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class)); Set<String> basePackages = getBasePackages(metadata); for (String basePackage : basePackages) { candidateComponents.addAll(scanner.findCandidateComponents(basePackage)); } } else { // 这里,通过EnableFeignClients中的clients()方法直接创建了BeanDefinition(BeanDefinition // 是非常重要的关于Bean的一个类,请阅读Spring源码) for (Class<?> clazz : clients) { // AnnotatedGenericBeanDefinition是BeanDefinition的实现类。 candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz)); } } for (BeanDefinition candidateComponent : candidateComponents) { if (candidateComponent instanceof AnnotatedBeanDefinition beanDefinition) { // verify annotated class is an interface AnnotationMetadata annotationMetadata = beanDefinition.getMetadata(); // 看到这个断言,@FeignClient只能直接接口 Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface");
Map<String, Object> attributes = annotationMetadata .getAnnotationAttributes(FeignClient.class.getCanonicalName());
String name = getClientName(attributes); String className = annotationMetadata.getClassName(); registerClientConfiguration(registry, name, className, attributes.get("configuration"));
registerFeignClient(registry, annotationMetadata, attributes); } } }
|
可以看到在registerFeignClients尝试获取EnableFeignClients注解,这里,并没有正式加载Feign client,只是获取一个全局的
配置,扫描包路径等,比较特殊的方法是clients(),直接获取关于@FeignClient的类。
接下来是注册Bean到容器,FeignClientRegister提供了两种注册,分别是eagerlyRegisterFeignClientBeanDefinition(className, attributes, registry)
和lazilyRegisterFeignClientBeanDefinition(className, attributes, registry),选择哪一种由
spring.cloud.openfeign.lazy-attributes-resolution决定,默认为false,使用eagerlyRegisterFeignClientBeanDefinition。
这里需要注意一点,不论哪一种方法,其实都是注册了一个FactoryBean的子类,并不是直接注册Feign Client。
最后,我们发现,Spring的openfeign依然是通过feignClientFactory完成。