Spring源碼-IOC容器(九)-Component-Scan源碼解析

Spring IOC容器 源碼解析系列,建議你們按順序閱讀,歡迎討論java

(spring源碼均爲4.1.6.RELEASE版本)node

  1. Spring源碼-IOC容器(一)-構建簡單IOC容器
  2. Spring源碼-IOC容器(二)-Bean的定位解析註冊
  3. Spring源碼-IOC容器(三)-GetBean
  4. Spring源碼-IOC容器(四)-FactoryBean
  5. Spring源碼-IOC容器(五)-Bean的初始化
  6. Spring源碼-IOC容器(六)-bean的循環依賴
  7. Spring源碼-IOC容器(七)-ApplicationContext
  8. Spring源碼-IOC容器(八)-NamespaceHandler與自定義xml
  9. Spring源碼-IOC容器(九)-Component-Scan源碼解析
  10. Spring源碼-IOC容器(十)-@Autowired解析

1.前言

如今的企業項目中使用spring時,大都不經過在xml中定義bean,由於實際項目下bean的定義繁多且依賴複雜,xml的方式會致使配置及更新困難。目前通常都經過簡單的xml和註解綜合使用的方式來對bean的定義和依賴進行配置。在這其中,包掃描就成爲註解方式必備的xml基本配置。經過掃描包來初步過濾出spring要管理的類,進而深刻地定義和組裝bean及其依賴關係。正則表達式

在spring的xml配置中,經過context命名空間下的component-scan標籤配置包掃描功能。而後在spring解析xml時調用context:component-scan的回調方法執行,關於context此類自定義命名空間的解析在Spring源碼-IOC容器(八)-NamespaceHandler與自定義xml一章已詳細講解過了。咱們直接經過ContextNamespaceHandler中對component-scan註冊的解析器來分析spring包掃描的過程。spring

2.ComponentScanBeanDefinitionParser

ContextNamespaceHandler的init方法中,註冊了各個子標籤對應的parser解析器,component-scan對應的爲ComponentScanBeanDefinitionParser。express

registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());

ComponentScanBeanDefinitionParser中對應的回調方法即parse方法。此方法定義在接口BeanDefinitionParser中。全部的parser解析器都會實現它來完成自定義的操做。來看下 ComponentScanBeanDefinitionParser的parse方法,結構很清晰。數組

ComponentScanBeanDefinitionParser.java

public BeanDefinition parse(Element element, ParserContext parserContext) {
	// 獲取base-packgage屬性
	String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
	// 對base-package的值中的${}進行解析並替換
	basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
	// 解析分隔符
	String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
			ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

	// 建立classpath掃描器
	ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
	// 執行掃描操做,返回組裝好的BeanDefinition集合
	Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
	// 根據配置註冊相關組件
	registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

	return null;
}

解析base-package

在spring-context.xsd中對base-package屬性要求是必填,而base-package的值支持${}的配置,僅僅只能解析系統屬性,包括System.getProperties()和System.getenv()中的屬性。對於經過spring中加載的properties資源是支持不了的(可見https://jira.spring.io/browse/SPR-4351)。而對於分隔符支持仍是比較豐富的,CONFIG_LOCATION_DELIMITERS的定義爲app

String CONFIG_LOCATION_DELIMITERS = ",; \t\n";

configureScanner

建立和配置classpath掃描器,經過configureScanner方法返回ClassPathBeanDefinitionScanneride

ComponentScanBeanDefinitionParser.java

protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
	// 是否使用默認過濾器(@Component註解)
	boolean useDefaultFilters = true;
	if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
		useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
	}

	// Delegate bean definition registration to scanner class.
	// 建立scan實例,設置默認過濾器
	ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
	scanner.setResourceLoader(parserContext.getReaderContext().getResourceLoader());
	scanner.setEnvironment(parserContext.getReaderContext().getEnvironment());
	scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
	scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());

	// 解析資源正則表達式,匹配類名稱
	if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {
		scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
	}

	try {
		// 解析bean名稱生成器
		parseBeanNameGenerator(element, scanner);
	}
	catch (Exception ex) {
		parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
	}

	try {
		// scope-resolver(scope解析器)以及scope-proxy(代理方式,默認爲no)
		parseScope(element, scanner);
	}
	catch (Exception ex) {
		parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
	}

	// include-filters和exclude-filters解析
	parseTypeFilters(element, scanner, parserContext);

	return scanner;
}

對因而否使用默認過濾器(useDefaultFilters),默認設置爲true,除非你有什麼特別的要求。在createScanner方法中實例化了ClassPathBeanDefinitionScanner,並在構造參數中傳入了useDefaultFilters,追溯其構造方法的實現,在父類ClassPathScanningCandidateComponentProvider的構造參數中,註冊了默認過濾器。post

public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment) {
	if (useDefaultFilters) {
		registerDefaultFilters();
	}
	Assert.notNull(environment, "Environment must not be null");
	this.environment = environment;
}

protected void registerDefaultFilters() {
	// @Component註冊過濾器
	this.includeFilters.add(new AnnotationTypeFilter(Component.class));
	ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
	try {
		// @ManagedBean過濾器
		this.includeFilters.add(new AnnotationTypeFilter(
				((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
		logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
	}
	catch (ClassNotFoundException ex) {
		// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
	}
	try {
		// @Named過濾器
		this.includeFilters.add(new AnnotationTypeFilter(
				((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
		logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
	}
	catch (ClassNotFoundException ex) {
		// JSR-330 API not available - simply skip.
	}
}

通常狀況下都是經過@Component來過濾,而@Repository,@Service,@Controller都是@Component的子類。若是須要格外添加的過濾條件,或者想排除特定的類,能夠經過字標籤context:include-filtercontext:exclude-filter來配置。好比想包含自定義的註解@SelfDefined,同時排除@Controller註解,能夠配置以下:ui

<context:component-scan base-package="com.lcifn.spring">
	<context:include-filter type="annotation" expression="com.lcifn.SelfDefined"/>
	<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

源碼中的解析過程也即上面的parseTypeFilters方法,對於不一樣的type生成不一樣的TypeFilter。

ComponentScanBeanDefinitionParser.java

protected void parseTypeFilters(Element element, ClassPathBeanDefinitionScanner scanner, ParserContext parserContext) {
	// Parse exclude and include filter elements.
	ClassLoader classLoader = scanner.getResourceLoader().getClassLoader();
	NodeList nodeList = element.getChildNodes();
	for (int i = 0; i < nodeList.getLength(); i++) {
		Node node = nodeList.item(i);
		if (node.getNodeType() == Node.ELEMENT_NODE) {
			String localName = parserContext.getDelegate().getLocalName(node);
			try {
				// include-filter
				if (INCLUDE_FILTER_ELEMENT.equals(localName)) {
					TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext);
					scanner.addIncludeFilter(typeFilter);
				}
				// exclude-filter
				else if (EXCLUDE_FILTER_ELEMENT.equals(localName)) {
					TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext);
					scanner.addExcludeFilter(typeFilter);
				}
			}
			catch (Exception ex) {
				parserContext.getReaderContext().error(
						ex.getMessage(), parserContext.extractSource(element), ex.getCause());
			}
		}
	}
}

doScan

拿到scanner掃描器後,真正執行掃描的操做。

ClassPathBeanDefinitionScanner.java

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
	Assert.notEmpty(basePackages, "At least one base package must be specified");
	Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
	for (String basePackage : basePackages) {
		// 掃描包路徑,找到全部候選者
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
		for (BeanDefinition candidate : candidates) {
			// 解析scope屬性
			ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
			candidate.setScope(scopeMetadata.getScopeName());
			// 生成bean名稱
			String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
			if (candidate instanceof AbstractBeanDefinition) {
				// 組裝BeanDefinition默認屬性
				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
			}
			if (candidate instanceof AnnotatedBeanDefinition) {
				// 解析類中的註解配置
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
			// 校驗同已註冊的BeanDefinition是否有衝突
			if (checkCandidate(beanName, candidate)) {
				BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
				// scope-proxy設置
				definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
				beanDefinitions.add(definitionHolder);
				// 註冊BeanDefinition到容器中
				registerBeanDefinition(definitionHolder, this.registry);
			}
		}
	}
	return beanDefinitions;
}

基本步驟就是先經過包路徑數組查找到全部的候選者,而後遍歷全部的候選者,設置scope屬性以及bean名稱,並設置BeanDefinition默認屬性以及經過註解設置的屬性。

查找候選者

根據base-package以及resource-pattern組裝出資源匹配表達式來匹配並讀取全部的class文件

ClassPathScanningCandidateComponentProvider.findCandidateComponents

String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
		resolveBasePackage(basePackage) + "/" + this.resourcePattern;
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);

獲取class文件的元信息,和全部TypeFilter進行匹配,匹配成功後建立ScannedGenericBeanDefinition,校驗class非接口非抽象,便可添加到候選者集合中。

ClassPathScanningCandidateComponentProvider.findCandidateComponents

// 獲取class文件元信息
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
// 匹配TypeFilter
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);
		}
	}
}

在匹配TypeFilter時,既要匹配includeFilter也要排除excludeFilter

ClassPathScanningCandidateComponentProvider.java

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

設置BeanDefinition默認屬性

ClassPathBeanDefinitionScanner.java

protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
	// 設置默認屬性
	beanDefinition.applyDefaults(this.beanDefinitionDefaults);
	if (this.autowireCandidatePatterns != null) {
		beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
	}
}

public void applyDefaults(BeanDefinitionDefaults defaults) {
	setLazyInit(defaults.isLazyInit()); // false
	setAutowireMode(defaults.getAutowireMode()); // AUTOWIRE_NO
	setDependencyCheck(defaults.getDependencyCheck());// DEPENDENCY_CHECK_NONE
	setInitMethodName(defaults.getInitMethodName()); // null
	setEnforceInitMethod(false);
	setDestroyMethodName(defaults.getDestroyMethodName());// null
	setEnforceDestroyMethod(false);
}

屬性註解

能夠經過在類中使用註解進行一些配置,包括@Lazy,@Primary,@DependsOn

AnnotationConfigUtils.java

static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
	if (metadata.isAnnotated(Lazy.class.getName())) {
		abd.setLazyInit(attributesFor(metadata, Lazy.class).getBoolean("value"));
	}
	else if (abd.getMetadata() != metadata && abd.getMetadata().isAnnotated(Lazy.class.getName())) {
		abd.setLazyInit(attributesFor(abd.getMetadata(), Lazy.class).getBoolean("value"));
	}

	if (metadata.isAnnotated(Primary.class.getName())) {
		abd.setPrimary(true);
	}
	if (metadata.isAnnotated(DependsOn.class.getName())) {
		abd.setDependsOn(attributesFor(metadata, DependsOn.class).getStringArray("value"));
	}

	if (abd instanceof AbstractBeanDefinition) {
		AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;
		if (metadata.isAnnotated(Role.class.getName())) {
			absBd.setRole(attributesFor(metadata, Role.class).getNumber("value").intValue());
		}
		if (metadata.isAnnotated(Description.class.getName())) {
			absBd.setDescription(attributesFor(metadata, Description.class).getString("value"));
		}
	}
}

註冊組件

包掃描以後只是將符合條件的類解析成BeanDefinition註冊到容器中,而在bean的實例化過程當中,每每須要依賴注入,依賴檢查之類的註解的解析操做,爲了不配置的冗雜,在component-scan標籤中有一個annotation-config的屬性,默認爲true,即加載全部常規註解的解析器。這個處理就在ComponentScanBeanDefinitionParser的registerComponents方法中。

// Register annotation config processors, if necessary.
	boolean annotationConfig = true;
	if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
		annotationConfig = Boolean.valueOf(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
	}
	if (annotationConfig) {
		Set<BeanDefinitionHolder> processorDefinitions =
				AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
		for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
			compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
		}
	}

核心的代碼在AnnotationConfigUtils.registerAnnotationConfigProcessors中

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
		BeanDefinitionRegistry registry, Object source) {

	DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
	if (beanFactory != null) {
		if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
			beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
		}
		if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
			beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
		}
	}

	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);

	// @Configuration註解解析器
	if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// @Autowired註解解析器
	if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// @Required註解解析器
	if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
	if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
	if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition();
		try {
			def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
					AnnotationConfigUtils.class.getClassLoader()));
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException(
					"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
		}
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	return beanDefs;
}

能夠看到主要的@Configuration,@Autowired,@Required的解析器,都是BeanFactoryPostProcessor或者BeanPostProcessor的子類,在這裏註冊到spring容器中。等到bean實例化的過程當中,在適當的時候對bean進行配置或調整。

到此component-scan的解析就結束了,但願你們能夠多看源碼,有所收穫。

相關文章
相關標籤/搜索