天天看點

6、注解bean的掃描

    通常我們需要開啟諸如@Component,@Service之類的注解,會在xml中配置一段這樣的标簽 這樣我們就可以在指定的包下面使用注解的方式建構bean了,context是自定義的一個命名空間,需要使用自定的方式進行解析,前面我們分析了自定義标簽的解析,我們知道spring要想解析自定标簽就必須通過一個命名空間解析器解析才能夠處理指定命名空間下定義的标簽,以下就是解析context命名空間的解析器。

public class ContextNamespaceHandler extends NamespaceHandlerSupport {

	@Override
	public void init() {
	    //以下就是context命名空間下的标簽處理器
		registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
		registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
		registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
		registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
		registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
	}

}
           

    上面定義了context命名空間下标簽處理器,本節主要研究component-scan标簽,可以看到處理這個标簽建立了ComponentScanBeanDefinitionParser處理器。

public BeanDefinition org.springframework.context.annotation.ComponentScanBeanDefinitionParser.parse(Element element, ParserContext parserContext) {
        //解析base-package
		String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
		//解析占位符
		basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
		//",; \t\n"分割
		String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

		// Actually scan for bean definitions and register them.
		//建立掃描器,掃描指定包下的class類
		ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
		//掃描BeanDefinition
		Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
		registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

		return null;
	}

           

    配置掃描器

protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
        //是否使用預設的過濾方式
		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.
		//new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters);
		ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
		//設定資源加載器
		scanner.setResourceLoader(parserContext.getReaderContext().getResourceLoader());
		//設定環境
		scanner.setEnvironment(parserContext.getReaderContext().getEnvironment());
		//設定預設的BeanDefinition屬性
		scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
		//設定自動裝配候選模式
		scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());
        //設定資源加載resource-pattern模式
		if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {
			scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
		}

		try {
		    //從元素中解析name-generator屬性,給掃描器設定beanName生成器
		    //是以我們可以實作自己的命名解析器
			parseBeanNameGenerator(element, scanner);
		}
		catch (Exception ex) {
			parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
		}

		try {
		    //解析scope,分為兩種,普通的scope,比如singleton這類
		    //還有一種是scopeProxy,分别是接口(JDK動态代理),目标類(cglib動态代理),NO(不做任何事情)
			parseScope(element, scanner);
		}
		catch (Exception ex) {
			parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
		}
        //解析include-filter标簽,建立類型過濾器
		parseTypeFilters(element, scanner, parserContext);

		return scanner;
	}
           

    在繼續往下研究之前,我們先來看下ClassPathBeanDefinitionScanner的類圖

6、注解bean的掃描
  1. Aware 标記接口
  2. EnvironmentCapable 定義擷取Environment的能力
  3. ResourceLoaderAware 定義設定ResourceLoader通知
  4. ClassPathScanningCandidateComponentProvider 掃描元件提供者,比如定義@Component掃描元件(預設關聯PathMatchingResourcePatternResolver,CachingMetadataReaderFactory)
  5. ClassPathBeanDefinitionScanner 提供BeanDefinition的掃描能力 (預設關聯AnnotationBeanNameGenerator[],AnnotationScopeMetadataResolver[會解析@Scope注解]的執行個體)
  6. ConditionEvaluator 條件執行器,由于過濾條件,對應使用的注解@Condition
  7. ConditionContextImpl 條件上下文,持有注冊器,環境,資源加載器,bean工廠

    其實在建立掃描器的時候,在構造器中做了以下的事情

protected void org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.registerDefaultFilters() {
        //添加@Component注解過濾器
		this.includeFilters.add(new AnnotationTypeFilter(Component.class));
		ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
		try {
		    //添加@ManagedBean注解,這種注解用于jsf,不過國内很少企業還會使用這種架構
			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.
		}
	}
           

    建立使用者指定過濾類型

protected TypeFilter createTypeFilter(Element element, ClassLoader classLoader, ParserContext parserContext) {
        //解析type屬性
		String filterType = element.getAttribute(FILTER_TYPE_ATTRIBUTE);
		//解析expression表達式
		String expression = element.getAttribute(FILTER_EXPRESSION_ATTRIBUTE);
		//解析占位符
		expression = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(expression);
		try {
		    //如果type指定是注解類型,那麼建立AnnotationTypeFilter,比對注解
			if ("annotation".equals(filterType)) {
				return new AnnotationTypeFilter((Class<Annotation>) classLoader.loadClass(expression));
			}
			//如果type指定assignable,建立AssignableTypeFilter,比對指定子類
			else if ("assignable".equals(filterType)) {
				return new AssignableTypeFilter(classLoader.loadClass(expression));
			}
			//如果type為aspectj,建立AspectJTypeFilter,使用切面表達式比對模式符比對
			else if ("aspectj".equals(filterType)) {
				return new AspectJTypeFilter(expression, classLoader);
			}
			//使用正規表達式比對,我們tvtaoadmin的項目似乎很鐘情于這種方式
			else if ("regex".equals(filterType)) {
				return new RegexPatternTypeFilter(Pattern.compile(expression));
			}
			//這種屬于自定義類型過濾器,我們隻要實作TypeFilter即可
			else if ("custom".equals(filterType)) {
				Class<?> filterClass = classLoader.loadClass(expression);
				if (!TypeFilter.class.isAssignableFrom(filterClass)) {
					throw new IllegalArgumentException(
							"Class is not assignable to [" + TypeFilter.class.getName() + "]: " + expression);
				}
				return (TypeFilter) BeanUtils.instantiateClass(filterClass);
			}
			else {
				throw new IllegalArgumentException("Unsupported filter type: " + filterType);
			}
		}
		catch (ClassNotFoundException ex) {
			throw new FatalBeanException("Type filter class not found: " + expression, ex);
		}
	}
           

    既然提到了TypeFilter,那麼我們來看下它的類圖

6、注解bean的掃描
  1. TypeFilter 定義比對某資源的能力
  2. CustomTypeFilter 自定義類型過濾器,比對包含Kustom的類名
  3. AspectJTypeFilter 使用切面表達式比對模式
  4. AbstractTypeHierarchyTraversingFilter 這是模闆類,AnnotationTypeFilter與AssignableTypeFilter都是有向上層比對的過程,這個類将這些能夠通用的代碼抽離,并使用猶如邏輯運算中短路的形式進行比對。
  5. AbstractClassTestingTypeFilter 也定義模闆方法
  6. RegexPatternTypeFilter 正則比對

    好了,到了這裡,一個ClassPathBeanDefinitionScanner掃描器就配置好了,接下來就看看它是怎麼掃描的。

protected Set<BeanDefinitionHolder> org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
		for (String basePackage : basePackages) {
		    //查找候選的bean
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
			    //使用scope解析器解析scope,預設是注解scope解析器,會解析類上的@Scope注解
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				//使用beanName生成器生成,預設是注解beanName生成器,會讀取諸如@Component上的value屬性,如果沒有指定value屬性值,那麼就使用類名的,第一個字母小寫,不會截取$$後面的字元,如果是一個$的,那麼替換為點
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				//如果它是AbstractBeanDefinition類型的,也就是用于表示一個bean的BeanDefinition(因為還有其他的不是表示bean的,比如PropertyValue這個是表示某個屬性名,對應某個值)
				if (candidate instanceof AbstractBeanDefinition) {
				    //将預設屬性設定進去,并判斷它是否用于自動裝配候選
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				//處理注解解析的BeanDefinition
				if (candidate instanceof AnnotatedBeanDefinition) {
			       //處理注解,比如從@Lazy注解擷取加載政策,@Primary表示是否為master bean	
    		   	AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				//檢查這個BeanDefinition是否已經存在,如果不存在,那麼傳回true,存在就判斷是否來自同一個檔案,如果不是,那麼就表示産生了沖突,會報錯,如果是,那麼傳回false,表示已經處理過了
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}
           

    上面是對尋找到的Bean進行進一步處理,裝飾,以下才是真正查找bean的過程。

public Set<BeanDefinition> org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
		try {
		    //解析占位符,拼接spring自定義的classpath*:協定,後面拼接Ant比對模式的**/*.class,這個模式我們可以在标簽的resource-pattern屬性進行手動指定,預設是**/*.class
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + "/" + this.resourcePattern;
			//這裡和分析spring查找xml配置檔案的時候是一樣的邏輯,隻不過是把字尾改成.class罷了,不再贅述
			Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			for (Resource resource : resources) {
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
				if (resource.isReadable()) {
					try {
					    //構造元素資料讀取器,内部使用ASM位元組碼架構實作位元組碼的讀取,不會對類進行加載。
						MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
						//判斷是否是我們想要的bean,我們在上面已經準備好了TypeFilter,這些TypeFilter将會在這裡使用,除此之外,内部還會@Conditional注解進行處理,也就是按條件按階段加載判斷是否加載bean
						if (isCandidateComponent(metadataReader)) {
						    //建立ScannedGenericBeanDefinition,這個類實作了AnnotationBeanDefinition,繼承了GenericBeanDefinition,具有擷取類注解的能力
							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);
							}
						。。。。。。省略部分代碼
		return candidates;
	}


           

    上面我們在掃描類的時候,看到了MetadataReader和MetadataReaderFactory類,很明顯MetadataReaderFactory是建構MetadataReader的工廠類,目前spring4.2.6中實作了MetadataReaderFactory的工廠是SimpleMetadataReaderFactory及其子類CachingMetadataReaderFactory,實作了MetadataReader接口的隻有SimpleMetadataReader,下面看下類圖

6、注解bean的掃描
  1. ClassMetadata 定義擷取類名,成員類,擷取超類等能力
  2. AnnotatedTypeMetadata 定義擷取注解的屬性,
  3. AnnotationMetadata 定義擷取注解的類型名,指定注解的元注解的屬性,擷取被指定注解标注的方法
  4. ClassVisitor 定義如何參觀一個類
  5. MetadataReaderFactory 定義建立MetadataReader,目前隻建立SimpleMetadataReader
  6. MetadataReader 定義讀取類資訊ClassMetadata,注解資訊AnnotationMetadata的能力

    ClassVisitor是一個參觀者,spring在這裡使用了參觀者模式,它被ClassReader接受。使用ClassVisitor可以操作類的資料,比如解析注解,方法,成員變量等。如果大家對ASM架構感興趣,可以到https://asm.ow2.io/官網學習,在學習ASM架構前,最後了解一下位元組碼檔案的格式和jvm指令,咱們繼續,等會我們會挑選一個TypeFilter來檢視它是怎麼比對的,比如AnnotationTypeFilter,這個類主要處理我們非常熟悉的@Component

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        //首先檢視這個類是否是排除的,如果是将不會加載為BeanDefinition
		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;
	}
           

    AnnotationTypeFilter比對,這個類繼承了AbstractTypeHierarchyTraversingFilter,這個類的match方法綜合了AssignableTypeFilter,AnnotationTypeFilter兩個類的比對功能,使用類似邏輯或的短路操作

public boolean org.springframework.core.type.filter.AbstractTypeHierarchyTraversingFilter.match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {

		// This method optimizes avoiding unnecessary creation of ClassReaders
		// as well as visiting over those readers.
		//首先比對自己的類上的注解,以及注解的元注解是否比對
		//元注解(比如@Service這個注解,實際上在掃描器的includeFilters這個集合裡并不存在對應的TypeFilter)
		//那麼它是怎麼比對上的呢?那是因為這個@Service注解上标有@Component注解,而這個注解被稱為元注解
		if (matchSelf(metadataReader)) {
			return true;
		}
		//如果這是一個AssignableTypeFilter執行個體,那麼上面直接傳回false
		//判斷設定的類是否為目前類或者是它的父類
		ClassMetadata metadata = metadataReader.getClassMetadata();
		if (matchClassName(metadata.getClassName())) {
			return true;
		}
        //如果考慮繼承,比如注解上存在@Inherited元注解,如果存在,那麼這裡為true
		if (this.considerInherited) {
		    //掃描超類,如果還是沒有找到,就會繼續向上
			if (metadata.hasSuperClass()) {
				// Optimization to avoid creating ClassReader for super class.
				Boolean superClassMatch = matchSuperClass(metadata.getSuperClassName());
				if (superClassMatch != null) {
					if (superClassMatch.booleanValue()) {
						return true;
					}
				}
				else {
					// Need to read super class to determine a match...
					try {
						if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
							return true;
						}
					}
					catch (IOException ex) {
						logger.debug("Could not read super class [" + metadata.getSuperClassName() +
								"] of type-filtered class [" + metadata.getClassName() + "]");
					}
 				}
			}
		}
        //如果考慮接口,那麼去比對接口,如果父接口沒有比對到,那麼繼續向上。
		if (this.considerInterfaces) {
			for (String ifc : metadata.getInterfaceNames()) {
				// Optimization to avoid creating ClassReader for super class
				Boolean interfaceMatch = matchInterface(ifc);
				if (interfaceMatch != null) {
					if (interfaceMatch.booleanValue()) {
						return true;
					}
				}
				else {
					// Need to read interface to determine a match...
					try {
						if (match(ifc, metadataReaderFactory)) {
							return true;
						}
					}
					catch (IOException ex) {
						logger.debug("Could not read interface [" + ifc + "] for type-filtered class [" +
								metadata.getClassName() + "]");
					}
				}
			}
		}

		return false;
	}
           

    即使類比對到了我們設定的TypeFilter,但這還不算完,這個類它自己有權利拒絕被加載,想要拒絕被加載的類上面會有@Conditional注解,這個注解告訴spring我必須滿足什麼樣的條件我才能被你加載。

private boolean isConditionMatch(MetadataReader metadataReader) {
		if (this.conditionEvaluator == null) {
			this.conditionEvaluator = new ConditionEvaluator(getRegistry(), getEnvironment(), getResourceLoader());
		}
		return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
	}
	
	
	public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {
	   //如果目前類的注解上不包含@Conditional,那麼直接傳回false
		if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
			return false;
		}

		if (phase == null) {
		    //如果目前類的注解包含@Configuration或者包含@Component,@ComponentScan,@Import,@ImportResource中的一個,或者是對應的方法上有@Bean注解,那麼認為目前為配置階段,否則為注冊bean階段,很顯然我們現在是在配置階段
			if (metadata instanceof AnnotationMetadata &&
					ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
				return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
			}
			return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
		}

		List<Condition> conditions = new ArrayList<Condition>();
		//從所有的注解@Conditional注解上擷取他們的value屬性清單,這個清單是實作了Condition接口的class類
		for (String[] conditionClasses : getConditionClasses(metadata)) {
			for (String conditionClass : conditionClasses) {
			    //通過反射的方式建構這個對象
				Condition condition = getCondition(conditionClass, this.context.getClassLoader());
				conditions.add(condition);
			}
		}
        
        //如果實作了優先級接口,按優先級在前排序,如果不是按實作的order接口的order值,如果也沒有實作order,如果傳入的是類那麼判斷是否存在@Order注解,如果沒有,再判斷@Priority,是方法也會判斷是否有@Order
		AnnotationAwareOrderComparator.sort(conditions);
        
		for (Condition condition : conditions) {
			ConfigurationPhase requiredPhase = null;
			if (condition instanceof ConfigurationCondition) {
				requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
			}
			//如果對階段有要求,那麼在對應的階段(比如配置階段)才能配置目前bean
			if (requiredPhase == null || requiredPhase == phase) {
				if (!condition.matches(this.context, metadata)) {
					return true;
				}
			}
		}

		return false;
	}
           

    通過以上的步驟,我們将我們需要的bean都擷取到了,那麼接下就是對每個掃描出來的bean進行進一步的配置,比如scope,lazy等屬性,對于scope這個屬性,如果我們沒有進行特殊的配置的話,那麼spring預設是AnnotationScopeMetadataResolver這個解析器,我們來大緻看下這個類是如果進行解析

public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
        //用于寄存解析出來的scope和scope代理模式
		ScopeMetadata metadata = new ScopeMetadata();
		//如果是使用了注解的BeanDefinition,那麼就會進行操作
		if (definition instanceof AnnotatedBeanDefinition) {
			AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
			//擷取目前注解類型的所有屬性值,這裡面涉及了spring的注解繼承原則
			//spring将元注解了解為目前注解的父注解,也就是說子注解可以重寫父注解的方法
			//比如@Service的元注解@Component就是@Service的父注解,出了value屬性以外,其他名字的屬性都能被@Service重寫
			AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(annDef.getMetadata(), this.scopeAnnotationType);
			if (attributes != null) {
			    //從@Scope注解中擷取scope,這裡需要注意一下别名,别名使用@AliasFor注解指定,是以在@Scope中我們可以設定value屬性,也可以設定scopeName屬性
				metadata.setScopeName(attributes.getAliasedString("value", this.scopeAnnotationType, definition.getSource()));
				//設定生命周期代理模式,像Web應用中有Request範圍
				//如果一個單例的Bean引用了一個Request範圍的bean
				//那該怎麼辦,那麼隻能通過代理的方式,才能保證每次調用
				//方法擷取的值是request範圍bean提供的。
				ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
				if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) {
					proxyMode = this.defaultProxyMode;
				}
				metadata.setScopedProxyMode(proxyMode);
			}
		}
		return metadata;
	}
           

    上面提到了@AliasFor這個注解,這個注解有一下幾個功能

  • 設定别名
    • 互為别名對的兩個屬性他們必須要有預設值,且預設值要一樣
    • 互為别名的兩個屬性不能同時指定值
  • 用于指定子注解覆寫父注解的某個屬性

    設定完scope之後,spring為這個這些BeanDefinition生成beanName,在沒有指定的情況下,使用的是AnnotationBeanNameGenerator生成器,這個生成器,首先通過注解上的value來擷取值,如果沒有就以bean的類名,首個字母小寫的作為beanName,如果是連續兩個大寫的,比如URL...這種,那麼原樣傳回,像RecommendService這種,就會變成recommendService。生成beanName之後對BeanDefinition進行了一些預設屬性的設定,@Lazy,@Primary,@DependsOn等通用注解的擷取。比較簡單,是以這裡不對它們進行分析。到了這裡還是不能馬上将BeanDefinition注冊到BeanFactory中,首先spring需要對這個BeanDefinition進行進一步的檢查。

protected boolean org.springframework.context.annotation.ClassPathBeanDefinitionScanner.checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
        //如果這個bean還未被注冊過,那麼傳回,進行裝飾,注冊
		if (!this.registry.containsBeanDefinition(beanName)) {
			return true;
		}
		//如果已經存在一個同名的BeanDefinition了
		BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
		BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
		//判斷是否被裝飾過,如果被裝飾過,那麼擷取最原始的BeanDefinition
		if (originatingDef != null) {
			existingDef = originatingDef;
		}
		//判斷是否是相容的
		if (isCompatible(beanDefinition, existingDef)) {
			return false;
		}
		throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
				"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
				"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
	}
           

    以上有段代碼判斷目前BeanDefinition是否和已經注冊過的BeanDefinition相容的代碼,spring将其分為三種情況,隻要滿足一個就視為相容:

1、已經注冊的bean不是掃描bean,也就是在配置檔案中明确指定的BeanDefinition

2、掃描的bean是同一個資源

3、兩者的BeanDefinition是equals的

    如果需要進行注冊,那麼首先需要對目前的BeanDefinition進行一次判斷,如果有設定生命周期代理模式,那麼就需要對目前BeanDefinition進行裝飾。

public static BeanDefinitionHolder org.springframework.aop.scope.ScopedProxyUtils.createScopedProxy(BeanDefinitionHolder definition,
			BeanDefinitionRegistry registry, boolean proxyTargetClass) {

		String originalBeanName = definition.getBeanName();
		BeanDefinition targetDefinition = definition.getBeanDefinition();
		//給目前的beanName加上scopedTarget.字首
		String targetBeanName = getTargetBeanName(originalBeanName);

		// Create a scoped proxy definition for the original bean name,
		// "hiding" the target bean in an internal target definition.
		//對目前BeanDefinition進行裝飾,ScopedProxyFactoryBean是一個實作了FactoryBean接口的類
		RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
		//設定被裝飾的bean定義
		proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
		//記錄最原始的BeanDefinition
		proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
		proxyDefinition.setSource(definition.getSource());
		proxyDefinition.setRole(targetDefinition.getRole());
        //添加targetBeanName屬性
		proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
		//如果使用cglib代理,給原始bean設定cglib代理辨別
		if (proxyTargetClass) {
			targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
			// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
		}
		else {
			proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
		}

		// Copy autowire settings from original bean definition.
		//将原始bean的值設定到裝飾bean中去
		proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
		//設定primary屬性
		proxyDefinition.setPrimary(targetDefinition.isPrimary());
		//設定qualified屬性
		if (targetDefinition instanceof AbstractBeanDefinition) {
			proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
		}

		// The target bean should be ignored in favor of the scoped proxy.
		//如果這個bean定義被代理了,那麼原始bean将不會再作為候選的bean提供給其他的bean注入
		targetDefinition.setAutowireCandidate(false);
		targetDefinition.setPrimary(false);

		// Register the target bean as separate bean in the factory.
		//使用帶有代理字首的beanName進行注冊
		registry.registerBeanDefinition(targetBeanName, targetDefinition);

		// Return the scoped proxy definition as primary bean definition
		// (potentially an inner bean).
		//将裝飾BeanDefinition作為主bean傳回
		return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
	}
           

    如果不需要裝飾就原樣傳回,如果要裝飾就進行裝飾,然後一切都已經準備就緒,可以進行注冊了。

public void org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
			    //進行校驗,不能同時出現工廠方法和方法覆寫代理方法
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

		BeanDefinition oldBeanDefinition;

		oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		if (oldBeanDefinition != null) {
		    //如果不允許BeanDefinition的覆寫,那麼會報錯,預設是運作的
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
						"': There is already [" + oldBeanDefinition + "] bound.");
			}
			。。。。。。省略部分代碼
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
		    //如果bean已經開始建立,說明此時已經是bean注冊階段,判斷的依據為alreadyCreated不為空
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				//加鎖,bean的建立注冊階段會有并發(tomcat在啟動context的時候是以一個線程池處理每個context的,此時不會有并發問題,但是如果tomcat已經完全啟動,那麼将會有并發問題)
				synchronized (this.beanDefinitionMap) {
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					//更新beanDefinitionNames集合
					this.beanDefinitionNames = updatedDefinitions;
					//如果記錄已注冊單例bean的beanName的集合已經包含這個bean的beanName,那麼移除它,這個manualSingletonNames目前我據我了解,它專門用于儲存那麼spring自己注冊的單例bean,他們沒有對應的BeanDefinition
					if (this.manualSingletonNames.contains(beanName)) {
						Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
						updatedSingletons.remove(beanName);
						this.manualSingletonNames = updatedSingletons;
					}
				}
			}
			else {
				// Still in startup registration phase
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				this.manualSingletonNames.remove(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}
        //移除與老的BeanDefinition相關聯的資料,比如合并過的BeanDefinition,注冊的bean,依賴,最後還會調用銷毀方法銷毀這些對象
		if (oldBeanDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

           

    以上就是我們配置的注解掃描過程,但這裡已經結束了,但是spring額外還做了一些事情。調用AnnotationConfigUtils.registerAnnotationConfigProcessors注冊注解配置

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, Object source) {
        
        //擷取BeanFactory,如果是applicationContext,那麼getBeanFactory
		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
		if (beanFactory != null) {
			if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
			    //設定依賴比較器,在擷取到集合依賴時進行排序
				beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
			}
			//設定自動裝配解析器,用于檢測是否是候選bean,構造懶加載代理bean(比如某個eager的bean依賴了一個懶加載的bean),解析@Value注解
			if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
				beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
			}
		}

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

		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		    //注冊ConfigurationClassPostProcessor //BeanDefinition後置處理器,實作了BeanDefinitionRegistryPostProcessor
		    //在加載完配置檔案後會調用,此時我們可以繼續配置BeanDefinition
		    //這裡用于解析@Configuration注解
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		    //注冊AutowiredAnnotationBeanPostProcessor後置處理器
		    //這個後置處理器用于處理@Autowire和@Value以及@Inject
			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		    //處理@Required
			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.
		//處理@WebServiceRef, @EJB, @Resource,jsr250Present這個變量是通過檢測@Resource注解是否存在
		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.
		//添加JPA支援,判斷是否存在@EntityManagerFactory和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));
		}
        //用于@EventListener的解析,使用ApplicationListenerMethodAdapter擴充卡進行包裝
		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
		}
		//定義建立ApplicationListenerMethodAdapter監聽器
		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
		}

		return beanDefs;
	}
           

    好了,@Component的掃描先告一段落了。

6、注解bean的掃描

總結:首先通過自定義标簽的命名空間擷取到處理這個命名空間的處理器,然後通過命名空間找到對應标簽元素的解析器進行解析,擷取元素标簽上設定的基路徑,加載對應目錄下的類資源,使用ASM架構去讀取類的中繼資料資訊,用預設的和自定義的TypeFilter去過濾這個類資源,最後注冊到BeanFactory中。

繼續閱讀