非默认标签解析的流程是一样的,都是先根据自己的命名空间找到对应的处理器,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这个标签的解析就完事了。