關於@EnableFeignClients的認識

今天起了大早,偶發現,項目忘記加入註解@EnableFeignClients,導致啓動失敗,於是想知道它做了啥呢?爲什麼項目沒有加載相關bean?

原來@EnableFeignClients是通過@Import把FeignClientsRegistrar注入到IOC容器中,當項目啓動執行

invokeBeanFactoryPostProcessors--》

invokeBeanDefinitionRegistryPostProcessors—》

ConfigurationClassPostProcessor調用processConfigBeanDefinitions方法執行parser.parse(candidates)的時候會調用掃描解析類ClassPathBeanDefinitionScanner默認掃描並默認加載啓動項包下的所有class(這裏出現了個疑問,是否系統只註冊@Component註解的類,這個問題一會看下代碼),之後在執行reader.loadBeanDefinitions的時候會調用其他註冊器進行註冊--》

ConfigurationClassBeanDefinitionReader有兩個方法,loadBeanDefinitionsFromImportedResources和loadBeanDefinitionsFromRegistrars,而本次使用的是loadBeanDefinitionsFromRegistrars,具體執行的註冊器是FeignClientsRegistrar

  註冊過程FeignClientsRegistrar

public void registerFeignClients(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
		ClassPathScanningCandidateComponentProvider scanner = getScanner();
		scanner.setResourceLoader(this.resourceLoader);

		Set<String> basePackages;

		Map<String, Object> attrs = metadata
				.getAnnotationAttributes(EnableFeignClients.class.getName());
		AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
				FeignClient.class);
		// 省略。。。。
		for (String basePackage : basePackages) {
			Set<BeanDefinition> candidateComponents = scanner
					.findCandidateComponents(basePackage);
			for (BeanDefinition candidateComponent : candidateComponents) {
				if (candidateComponent instanceof AnnotatedBeanDefinition) {
					 // 省略。。。。
                    // 這裏找到客戶端FeignClient註解,準備註冊到            DefaultListableBeanFactory容器裏
					Map<String, Object> attributes = annotationMetadata
							.getAnnotationAttributes(
									FeignClient.class.getCanonicalName());

					String name = getClientName(attributes);
					registerClientConfiguration(registry, name,
							attributes.get("configuration"));

					registerFeignClient(registry, annotationMetadata, attributes);
				}
			}
		}
	}
private void registerFeignClient(BeanDefinitionRegistry registry,
			AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
		String className = annotationMetadata.getClassName();
		BeanDefinitionBuilder definition = BeanDefinitionBuilder
				.genericBeanDefinition(FeignClientFactoryBean.class);
		validate(attributes);
		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 });
        // 註冊Feign客戶端到DefaultListableBeanFactory容器,這樣啓動後就能通過@Autowired注入,否則無法啓動
		BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
	}

ClassPathBeanDefinitionScanner分析是否系統只註冊@Component註解的類

省略其中調用過程,直接進入ClassPathScanningCandidateComponentProvider分析doScan方法,緊接着進入scanCandidateComponents,顧名思義應該就是隻註冊@Component註解的類,

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>(); 
            // 省略。。。。
			for (Resource resource : resources) {
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
				if (resource.isReadable()) {
					try {
						MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                        // 過濾條件
						if (isCandidateComponent(metadataReader)) {
							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
							sbd.setResource(resource);
							sbd.setSource(resource);
							if (isCandidateComponent(sbd)) {
								if (debugEnabled) {
									logger.debug("Identified candidate component class: " + resource);
								}
								candidates.add(sbd);
							}
							else {
								if (debugEnabled) {
									logger.debug("Ignored because not a concrete top-level class: " + resource);
								}
							}
						}
						// 省略。。。。
			 
		return candidates;
	}

過濾條件中includeFileter包括Component:

確定給定的類是否與任何排除篩選器不匹配
與至少一個包含篩選器匹配。

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
		for (TypeFilter tf : this.excludeFilters) {
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				return false;
			}
		}
		for (TypeFilter tf : this.includeFilters) {
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				return isConditionMatch(metadataReader);
			}
		}
		return false;
	}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章