spring-mvc源码-bean定义加载-非默认标签解析(context:component-scan)

非默认标签解析的流程是一样的,都是先根据自己的命名空间找到对应的处理器,context:component-scan这个标签的命名空间是http://www.springframework.org/schema/context,根据这个命名空间可以找到对应的处理器:ContextNamespaceHandler,然后再找到对应的解析器解析,具体源代码可以参阅:https://blog.csdn.net/matt8/article/details/106643583

我们从解析器的解析开始看,最终拿到的对应context:component-scan这个标签的解析器是ComponentScanBeanDefinitionParser,对应的解析方法是parse,基本上spring的组件都是面向接口的,解析器接口是:org.springframework.beans.factory.xml.BeanDefinitionParser,在beans包中,面向接口乃是实现可扩展框架的不二法门啊。

先看下这个解析器支持的属性,都在这个类的私有静态变量里了:

	private static final String BASE_PACKAGE_ATTRIBUTE = "base-package";

	private static final String RESOURCE_PATTERN_ATTRIBUTE = "resource-pattern";

	private static final String USE_DEFAULT_FILTERS_ATTRIBUTE = "use-default-filters";

	private static final String ANNOTATION_CONFIG_ATTRIBUTE = "annotation-config";

	private static final String NAME_GENERATOR_ATTRIBUTE = "name-generator";

	private static final String SCOPE_RESOLVER_ATTRIBUTE = "scope-resolver";

	private static final String SCOPED_PROXY_ATTRIBUTE = "scoped-proxy";

	private static final String EXCLUDE_FILTER_ELEMENT = "exclude-filter";

	private static final String INCLUDE_FILTER_ELEMENT = "include-filter";

	private static final String FILTER_TYPE_ATTRIBUTE = "type";

	private static final String FILTER_EXPRESSION_ATTRIBUTE = "expression";

看下org.springframework.context.annotation.ComponentScanBeanDefinitionParser#parse的源码:

	public BeanDefinition parse(Element element, ParserContext parserContext) {
		//获取包路径
		String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
		//如果包路径有环境变量,用实际的值替换
		basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
		//包路径转换成数组,说明可以支持多个,以",; \t\n"这些符号分隔
		String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

		//创建扫描器
		ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
		//通过扫描器扫描来获取包名下的所有class并将他们注册到spring的容器中
		Set beanDefinitions = scanner.doScan(basePackages);
		//注册其他注解组件
		registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

		return null;
	}

主要看下创建扫描器、扫描包和注册其他注解组件这三个方法。

org.springframework.context.annotation.ComponentScanBeanDefinitionParser#configureScanner方法源码:

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

		//这里会把useDefaultFilters传进去,默认为true,表示会对@Component、@Repository、@Service、@Controller和 JavaEE6的@ManagedBean和@Named这些注解进行扫描处理
		//其中@Component这个注解与@Repository、@Service、@Controller这三注解等价
		ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
		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’属性指定的bean name生成器
			parseBeanNameGenerator(element, scanner);
		}
		catch (Exception ex) {
			parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
		}

		try {
			//设置‘scope-resolver’属性指定的自定义作用域解析器
			//设置‘scoped-proxy’属性指定的代理模式,有三个值选项,no:默认值,interfaces:接口代理jdk,targetClass:类代理cglib,那什么时候需要用到scope代理呢,举个例子,我们知道Bean的作用域有singleton,prototype,request,session,
			//那有这么一种情况,当你把一个session或者request的Bean注入到singleton的Bean中时,因为singleton的Bean在容器启动时就会创建A,而session的Bean在用户访问时才会创建B,那么当A中要注入B时,有可能B还未创建,这个时候就会出问题,spring用代理解决//这个问题,B如果是接口,就用interfaces代理,是类则用targetClass代理。scope-resolver与scoped-proxy只能配置一个
			parseScope(element, scanner);
		}
		catch (Exception ex) {
			parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
		}
		//解析子节点`context:include-filter`、`context:exclude-filter`,设置对应的过滤器
		parseTypeFilters(element, scanner, parserContext);

		return scanner;
	}

接着是扫描器扫描包下的所有类,并注册到容器,看doScan方法:

	protected Set doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set beanDefinitions = new LinkedHashSet();
		for (String basePackage : basePackages) {
			//加载包下的所有类,找到符合条件的类生成BeanDefinition,符合条件包括两项:1、默认的设置的:被@Component或者@Named及其子注解注解的类,2、子节点`context:include-filter`、`context:exclude-filter`设置的
			Set candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				//解析一个bean的scope属性,默认是singleton
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				//从注解上获取bean name,没有话生成一个,例如:"mypackage.MyJdbcDao" -> "myJdbcDao"
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				if (candidate instanceof AbstractBeanDefinition) {
					//给beanDefinition设置默认值,设置此bean是否可以自动装配到其他bean中, 默认为true
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition) {
					//读取bean上的注解,比如@Lazy、@Primary、@Dependson、@Role、@Description的值设置到BeanDefinition上
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				//检查容器中是否已注册
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					//根据作用域@Scope的值决定是否使用代理及使用哪种代理,这里只是生成代理bean的定义
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					//将bean定义注册到容器
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

最后一步,向容器注册后置处理器,registerComponents方法如下:

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

		Object source = readerContext.extractSource(element);
		//包装CompositeComponentDefinition
		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;
		//获取annotation-config的属性值,默认为true
		if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
			annotationConfig = Boolean.valueOf(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
		}
		if (annotationConfig) {
			//注册后置处理器,与调用的是同一个方法,具体参考:https://blog.csdn.net/matt8/article/details/106643583
			//从这里可以看出,在annotation-config属性为true的情况下,包含了的所有功能,这个时候就是多余的
			Set processorDefinitions =
					AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
			for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
				compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
			}
		}

		//用于BeanDefinition注册完成事件通知,是空实现
		readerContext.fireComponentRegistered(compositeDef);
	}

至此,context:component-scan这个标签的解析就完事了。

你可能感兴趣的:(源码系列,spring)