5.SpringMVC源码关于annotation扫描3

扫描器加载basePackages

再次回顾,ComponentScanBeanDefinitionParser这个类中的parse(),之前描述了配置扫描器configureScanner(),我们接着了解一下扫描器是如何加载这些包类的。

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
	String[] basePackages = StringUtils.tokenizeToStringArray(element.getAttribute(BASE_PACKAGE_ATTRIBUTE),
			ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

	// Actually scan for bean definitions and register them.
	ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
	Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
	registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

	return null;
}

scanner.doScan(basePackages)是对之前循环扫描到的包数组的解析,我们把包数组传递进来,去看它的实现。

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) {
			ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
			candidate.setScope(scopeMetadata.getScopeName());
			String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
			if (candidate instanceof AbstractBeanDefinition) {
				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
			}
			if (candidate instanceof AnnotatedBeanDefinition) {
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
			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;
}

通过包数组循环取出单个的包,这里获取到的String basePackage是包的路径,类似于这种的com.zhuang.action。然后进入findCandidateComponents(basePackage)具体的看一下

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
	Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
	try {
		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				resolveBasePackage(basePackage) + "/" + this.resourcePattern;
		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 {
					MetadataReader metadataReader = this.metadataReaderFactory.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);
							}
						}
					}
					else {
						if (traceEnabled) {
							logger.trace("Ignored because not matching any filter: " + resource);
						}
					}
				}
				catch (Throwable ex) {
					throw new BeanDefinitionStoreException(
							"Failed to read candidate component class: " + resource, ex);
				}
			}
			else {
				if (traceEnabled) {
					logger.trace("Ignored because not readable: " + resource);
				}
			}
		}
	}
	catch (IOException ex) {
		throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
	}
	return candidates;
}

其中try方法中第一句代码就是把我们传进来的包路径由.转化为/

String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				resolveBasePackage(basePackage) + "/" + this.resourcePattern;

ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX这是在包路径前拼接一个classpath*:

resolveBasePackage(basePackage)点进去

protected String resolveBasePackage(String basePackage) {
	return ClassUtils.convertClassNameToResourcePath(this.environment.resolveRequiredPlaceholders(basePackage));
}

public static String convertClassNameToResourcePath(String className) {
	Assert.notNull(className, "Class name must not be null");
	return className.replace('.', '/');
}

这样就可以看到className.replace('.', '/'),返回的是一个com/zhuang/action这种效果,这样就变成了classpath*:com/zhuang/action

后面的+ "/" + this.resourcePattern, this.resourcePattern我们发现是**/*.class,最终的String packageSearchPath=classpath*:com/zhuang/action/**/*.class。之后用this.resourcePatternResolver.getResources获取具体的class文件,封装成resource对象。在这个resource对象中,最主要的还是在其父类InputStreamSource有一个输入流的方法InputStream getInputStream()。看一下this.resourcePatternResolver.getResources(packageSearchPath),在PathMatchingResourcePatternResolver.java中

@Override
public Resource[] getResources(String locationPattern) throws IOException {
	Assert.notNull(locationPattern, "Location pattern must not be null");
	if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
		// a class path resource (multiple resources for same name possible)
		if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
			// a class path resource pattern
			return findPathMatchingResources(locationPattern);
		}
		else {
			// all class path resources with the given name
			return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
		}
	}
	else {
		// Only look for a pattern after a prefix here
		// (to not get fooled by a pattern symbol in a strange prefix).
		int prefixEnd = locationPattern.indexOf(":") + 1;
		if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
			// a file pattern
			return findPathMatchingResources(locationPattern);
		}
		else {
			// a single resource with the given name
			return new Resource[] {getResourceLoader().getResource(locationPattern)};
		}
	}
}

locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)判断包路径内有没有classpath*:,如果有截取classpath*:之后的路径com/zhuang/action/**/*.class。如果没有classpath*:,从下标0开始截取字符串。最终执行的是findPathMatchingResources(locationPattern)或findAllClassPathResources()。这个方法其实就是获取包路径,然后通过包路径获取file对象,获取file对象的list,list为包路径下的所有文件夹以及文件。如果是文件夹的话,再次递归的调用该方法,如果不是获取最终class文件的路径。

protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
	String rootDirPath = determineRootDir(locationPattern);
	String subPattern = locationPattern.substring(rootDirPath.length());
	Resource[] rootDirResources = getResources(rootDirPath);
	Set<Resource> result = new LinkedHashSet<Resource>(16);
	for (Resource rootDirResource : rootDirResources) {
		rootDirResource = resolveRootDirResource(rootDirResource);
		if (rootDirResource.getURL().getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
			result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirResource, subPattern, getPathMatcher()));
		}
		else if (isJarResource(rootDirResource)) {
			result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern));
		}
		else {
			result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
		}
	}
	if (logger.isDebugEnabled()) {
		logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result);
	}
	return result.toArray(new Resource[result.size()]);
}

循环获取rootDirResource 进行判断是vfs、jar还是Class文件,主要看一下针对于class文件的一个解析result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));解析完加入到Set<Resource> result里面去,看一下doFindPathMatchingFileResources()

protected Set<Resource> doFindPathMatchingFileResources(Resource rootDirResource, String subPattern)
		throws IOException {

	File rootDir;
	try {
		rootDir = rootDirResource.getFile().getAbsoluteFile();
	}
	catch (IOException ex) {
		if (logger.isWarnEnabled()) {
			logger.warn("Cannot search for matching files underneath " + rootDirResource +
					" because it does not correspond to a directory in the file system", ex);
		}
		return Collections.emptySet();
	}
	return doFindMatchingFileSystemResources(rootDir, subPattern);
}

返回一个doFindMatchingFileSystemResources(rootDir, subPattern)进去看一下

protected Set<Resource> doFindMatchingFileSystemResources(File rootDir, String subPattern) throws IOException {
	if (logger.isDebugEnabled()) {
		logger.debug("Looking for matching resources in directory tree [" + rootDir.getPath() + "]");
	}
	Set<File> matchingFiles = retrieveMatchingFiles(rootDir, subPattern);
	Set<Resource> result = new LinkedHashSet<Resource>(matchingFiles.size());
	for (File file : matchingFiles) {
		result.add(new FileSystemResource(file));
	}
	return result;
}

看一下第一个有效的方法retrieveMatchingFiles(rootDir, subPattern);进去看一下

protected Set<File> retrieveMatchingFiles(File rootDir, String pattern) throws IOException {
	if (!rootDir.exists()) {
		// Silently skip non-existing directories.
		if (logger.isDebugEnabled()) {
			logger.debug("Skipping [" + rootDir.getAbsolutePath() + "] because it does not exist");
		}
		return Collections.emptySet();
	}
	if (!rootDir.isDirectory()) {
		// Complain louder if it exists but is no directory.
		if (logger.isWarnEnabled()) {
			logger.warn("Skipping [" + rootDir.getAbsolutePath() + "] because it does not denote a directory");
		}
		return Collections.emptySet();
	}
	if (!rootDir.canRead()) {
		if (logger.isWarnEnabled()) {
			logger.warn("Cannot search for matching files underneath directory [" + rootDir.getAbsolutePath() +
					"] because the application is not allowed to read the directory");
		}
		return Collections.emptySet();
	}
	String fullPattern = StringUtils.replace(rootDir.getAbsolutePath(), File.separator, "/");
	if (!pattern.startsWith("/")) {
		fullPattern += "/";
	}
	fullPattern = fullPattern + StringUtils.replace(pattern, File.separator, "/");
	Set<File> result = new LinkedHashSet<File>(8);
	doRetrieveMatchingFiles(fullPattern, rootDir, result);
	return result;
}

一开始SpringMVC对我们路径的各种情况做了一个判断,主要的代码还是下面这段

String fullPattern = StringUtils.replace(rootDir.getAbsolutePath(), File.separator, "/");
if (!pattern.startsWith("/")) {
	fullPattern += "/";
}
fullPattern = fullPattern + StringUtils.replace(pattern, File.separator, "/");
Set<File> result = new LinkedHashSet<File>(8);
doRetrieveMatchingFiles(fullPattern, rootDir, result);

fullPattern最终还是转换为一个以/标识的绝对路径,然后进入doRetrieveMatchingFiles(fullPattern, rootDir, result)

protected void doRetrieveMatchingFiles(String fullPattern, File dir, Set<File> result) throws IOException {
	if (logger.isDebugEnabled()) {
		logger.debug("Searching directory [" + dir.getAbsolutePath() +
				"] for files matching pattern [" + fullPattern + "]");
	}
	File[] dirContents = dir.listFiles();
	if (dirContents == null) {
		if (logger.isWarnEnabled()) {
			logger.warn("Could not retrieve contents of directory [" + dir.getAbsolutePath() + "]");
		}
		return;
	}
	for (File content : dirContents) {
		String currPath = StringUtils.replace(content.getAbsolutePath(), File.separator, "/");
		if (content.isDirectory() && getPathMatcher().matchStart(fullPattern, currPath + "/")) {
			if (!content.canRead()) {
				if (logger.isDebugEnabled()) {
					logger.debug("Skipping subdirectory [" + dir.getAbsolutePath() +
							"] because the application is not allowed to read the directory");
				}
			}
			else {
				doRetrieveMatchingFiles(fullPattern, content, result);
			}
		}
		if (getPathMatcher().match(fullPattern, currPath)) {
			result.add(content);
		}
	}
}

这里就是我们之前所说的获取路径的file对象,获取file对象的list。然后循环进行检测是否是文件夹,如果是进行递归再次调用doRetrieveMatchingFiles(fullPattern, content, result),最终获取到class的完整路径,加入到result中。然后回到之前的set<file> result中

protected Set<Resource> doFindMatchingFileSystemResources(File rootDir, String subPattern) throws IOException {
	if (logger.isDebugEnabled()) {
		logger.debug("Looking for matching resources in directory tree [" + rootDir.getPath() + "]");
	}
	Set<File> matchingFiles = retrieveMatchingFiles(rootDir, subPattern);
	Set<Resource> result = new LinkedHashSet<Resource>(matchingFiles.size());
	for (File file : matchingFiles) {
		result.add(new FileSystemResource(file));
	}
	return result;
}

然后再循环加入到set<Resource> result直接return。

protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
	String rootDirPath = determineRootDir(locationPattern);
	String subPattern = locationPattern.substring(rootDirPath.length());
	Resource[] rootDirResources = getResources(rootDirPath);
	Set<Resource> result = new LinkedHashSet<Resource>(16);
	for (Resource rootDirResource : rootDirResources) {
		rootDirResource = resolveRootDirResource(rootDirResource);
		if (rootDirResource.getURL().getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
			result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirResource, subPattern, getPathMatcher()));
		}
		else if (isJarResource(rootDirResource)) {
			result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern));
		}
		else {
			result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
		}
	}
	if (logger.isDebugEnabled()) {
		logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result);
	}
	return result.toArray(new Resource[result.size()]);
}

这样就把class文件全都变成了对应的resource对象。接着我们回到之前的findCandidateComponents(String basePackage)

	public Set<BeanDefinition> findCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
		try {
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + "/" + this.resourcePattern;
			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 {
						MetadataReader metadataReader = this.metadataReaderFactory.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);
								}
							}
						}
						else {
							if (traceEnabled) {
								logger.trace("Ignored because not matching any filter: " + resource);
							}
						}
					}
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to read candidate component class: " + resource, ex);
					}
				}
				else {
					if (traceEnabled) {
						logger.trace("Ignored because not readable: " + resource);
					}
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}

其中this.metadataReaderFactory.getMetadataReader(resource)经过循环,把我们的所有获取到的resource对象含有注解的,封装到我们的MetadataReader 中,点进MetadataReader 中我们看一下

public interface MetadataReader {

	/**
	 * Return the resource reference for the class file.
	 */
	Resource getResource();

	/**
	 * Read basic class metadata for the underlying class.
	 */
	ClassMetadata getClassMetadata();

	/**
	 * Read full annotation metadata for the underlying class,
	 * including metadata for annotated methods.
	 */
	AnnotationMetadata getAnnotationMetadata();

}

看一下最后一个方法的注释Read full annotation metadata for the underlying class, including metadata for annotated methods,正式这个AnnotationMetadata getAnnotationMetadata()方法,把我们的注解封装到MetadataReader 中,之后isCandidateComponent(metadataReader)过滤所有的刚才@Controller,@Service等四个注解,获取到的metadataReader存放入新new的ScannedGenericBeanDefinition对象中,ScannedGenericBeanDefinition 是一个BeanDefinition对象,因为它实现AbstractBeanDefinition和AnnotatedBeanDefinition,最后加入到set<BeanDefinition> candidates 

我们继续返回doScan(String... basePackages) ,之前一直说的是findCandidateComponents(basePackage)中的内容,现在返回了一个Set<BeanDefinition> candidates 

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) {
			ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
			candidate.setScope(scopeMetadata.getScopeName());
			String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
			if (candidate instanceof AbstractBeanDefinition) {
				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
			}
			if (candidate instanceof AnnotatedBeanDefinition) {
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
			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;
}

接下来,SpringMVC针对返回的BeanDefinition做了一些处理,循环获取到的BeanDefinition判断是什么类型的。如果判断BeanDefinition是一个AnnotatedBeanDefinition的话,执行AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate)点进去看一下

public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
	processCommonDefinitionAnnotations(abd, abd.getMetadata());
}

再进入processCommonDefinitionAnnotations(abd, abd.getMetadata())中

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().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"));
		}
	}
}

然后把初始化属性、懒加载等配置在这里配置进去,同XML中的<bean>标签,使用效果是一样的。之后返回到doScan(String... basePackages)中

		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;

把beanname和annotationbeandefition封装成definitionholder,然后又加入到beandefinitions中,进行注册,在registerBeanDefinition(definitionHolder, this.registry)

protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}

再进入BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry)

public static void registerBeanDefinition(
		BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
		throws BeanDefinitionStoreException {

	// Register bean definition under primary name.
	String beanName = definitionHolder.getBeanName();
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

	// Register aliases for bean name, if any.
	String[] aliases = definitionHolder.getAliases();
	if (aliases != null) {
		for (String aliase : aliases) {
			registry.registerAlias(beanName, aliase);
		}
	}
}

在registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())进行注册

public void 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;

	synchronized (this.beanDefinitionMap) {
		oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		if (oldBeanDefinition != null) {
			if (!this.allowBeanDefinitionOverriding) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
						"': There is already [" + oldBeanDefinition + "] bound.");
			}
			else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (this.logger.isWarnEnabled()) {
					this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
							" with a framework-generated bean definition ': replacing [" +
							oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else {
				if (this.logger.isInfoEnabled()) {
					this.logger.info("Overriding bean definition for bean '" + beanName +
							"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
		}
		else {
			this.beanDefinitionNames.add(beanName);
			this.frozenBeanDefinitionNames = null;
		}
		this.beanDefinitionMap.put(beanName, beanDefinition);
	}

	if (oldBeanDefinition != null || containsSingleton(beanName)) {
		resetBeanDefinition(beanName);
	}
}

主要的就是把我们的beanname和beandefinition缓存到beandefinitionMap中,返回到ComponentScanBeanDefinitionParser.parse(Element element, ParserContext parserContext)

public BeanDefinition parse(Element element, ParserContext parserContext) {
	String[] basePackages = StringUtils.tokenizeToStringArray(element.getAttribute(BASE_PACKAGE_ATTRIBUTE),
			ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

	// Actually scan for bean definitions and register them.
	ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
	Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
	registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

	return null;
}

这就是我们Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages)的源码内容。

兼容annotation-config

registerComponents(parserContext.getReaderContext(), beanDefinitions, element)是我们component-scan对annotation-config的兼容,也就是配置了component-scan就可以不用配置annotation-config,详细了解一下

protected void registerComponents(
		XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {

	Object source = readerContext.extractSource(element);
	CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);

	for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
		compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
	}

	// 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));
		}
	}

	readerContext.fireComponentRegistered(compositeDef);
}

这里设置了一个默认值boolean annotationConfig = true,检查是否有这个属性,除非特意在component-scan中设置了annotation-config=false。注册AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source)

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);

	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));
	}

	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));
	}

	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;
}

这里面增加了关于@PostConstruct,@PreDestroy、@Resource、@Configuration、@Autowired、@Required、@PersistenceUnit和@PersistenceContext,把所属的classloader和classname加入到RootBeanDefinition,然后在进行registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)注册,同之前的注册方法一样,缓存到map中。

这就是整个的获取注解的过程

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringMVC框架内置了一些对象,这些对象可以在控制器中直接使用。以下是一些常用的SpringMVC内置对象: 1. HttpServletRequest:表示HTTP请求的对象,可以用于获取请求的参数、头信息等。 2. HttpServletResponse:表示HTTP响应的对象,可以用于设置响应的状态码、头信息等。 3. HttpSession:表示HTTP会话的对象,可以用于在不同请求之间共享数据。 4. Model:用于在控制器中存储数据,这些数据可以在视图中进行展示。 5. ModelAndView:用于同时存储数据和视图信息的对象。 6. RedirectAttributes:用于在重定向时传递数据。 这些内置对象可以通过方法参数或注解来获取或使用。例如,可以在控制器方法中添加HttpServletRequest参数来获取请求对象,或者使用@ModelAttribute注解来获取请求参数并绑定到模型对象中。 以下是一个示例,演示了如何在SpringMVC控制器中使用内置对象: ```java @Controller public class MyController { @RequestMapping("/example") public String example(HttpServletRequest request, Model model) { // 使用HttpServletRequest对象获取请求参数 String param = request.getParameter("param"); // 使用Model对象存储数据 model.addAttribute("param", param); return "exampleView"; } } ``` 在上面的示例中,控制器方法"example"接收一个HttpServletRequest对象和一个Model对象作为参数。通过HttpServletRequest对象可以获取请求参数,然后将参数存储到Model对象中,最后返回一个视图名"exampleView"。视图名将被解析为具体的视图模板,用于展示数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值