上一节已经详细的看了一下默认标签的解析了,这一节我们来看一下自定义标签是如何解析的。
首先,来看一下自定义标签解析的入口方法,delegate.parseCustomElement(ele):
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
//根据标签获取其名称空间
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
//通过nameSpaceUri初始化一个NamespaceHandler
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
//解析标签
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
继续进入解析标签的逻辑,handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)):
public BeanDefinition parse(Element element, ParserContext parserContext) {
//这里根据element在handler中获取对应的解析器
BeanDefinitionParser parser = findParserForElement(element, parserContext);
//使用BeanDefinitionParser解析器来解析element
return (parser != null ? parser.parse(element, parserContext) : null);
}
我这边跟代码的时候使用的自定义标签是component-scan
,获取到的解析器为ComponentScanBeanDefinitionParser
继续进入解析器解析element的代码,parser.parse(element, parserContext):
public BeanDefinition parse(Element element, ParserContext parserContext) {
//获取component-scan标签的base-package的值
String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
//解析basePackage的结果,如果没有${,那么直接返回,如果有,则去配置文件中解析
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
//根据,;进行切割
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
// 初始化一个scanner对象,包括设置该标签中对应的属性和子标签的定义
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
//扫描包,并生成对应的beanDefinition
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
/**将上一步的扫描结果注册到applicationContext,并且将默认的几个beanDefinition也初始化,并注册
* 1. ConfigurationClassPostProcessor
* 2. AutowiredAnnotationBeanPostProcessor
* 3. CommonAnnotationBeanPostProcessor
* 4. EventListenerMethodProcessor
* 5. DefaultEventListenerFactory
* 关于这5个默认的beanDefinition,以后会做详细的介绍(例如第一个ConfigurationClassPostProcessor就是Configuration注解的实现)
*/
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<>();
for (String basePackage : basePackages) {
//扫描出所有的被component注解标注的类,将解析成beanDefinition
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
//设置beanDefinition的scope属性,默认是singleton
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
//设置一些beanDefinition的默认属性,如懒加载,autowiredMode等
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
//设置beanDefinition的其他的一些属性,如primary,depend-on,role等
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
//判断是否已经被注册过
if (checkCandidate(beanName, candidate)) {
//没有注册
//将beanDefinition包装成definitionHolder
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
//将definitionHolder注册到applicationContext,逻辑同默认标签的注册是一样的
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
进入findCandidateComponents(basePackage):
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
componentsIndex是空的,所以会直接进入到else,scanCandidateComponents(basePackage):
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
//将包名包装成指定的包名和子包
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//解析出指定包和子包下的所有的文件的resource对象
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
for (Resource resource : resources) {
if (resource.isReadable()) {
try {
//将resource对象(记录了class文件的信息)抽象成元数据对象
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//判断是否有Component注解标注
if (isCandidateComponent(metadataReader)) {
//更具元数据初始化一个beanDefintion
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
//判断是否是component标注的beanDefinition,如果是,则添加到返回结果中
if (isCandidateComponent(sbd)) {
candidates.add(sbd);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
这边我们分别来看看如何判断元数据对象和beanDefinition对象是否是component标注的,isCandidateComponent(metadataReader):
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
//默认是空的
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
//如果类的注解中存在component名字的注解
if (tf.match(metadataReader, getMetadataReaderFactory())) {
//内部逻辑是会初始化一个conditionEvaluator(条件评估对象),判断是否需要跳过不加载
//就是判断是否被conditional注解标注,如果有,判断值的内容,看是否需要跳过
return isConditionMatch(metadataReader);
}
}
return false;
}
下面再来看看如何判断beanDefinition对象是否是component标注的,isCandidateComponent(sbd):
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
/**
* metadata.isIndependent():不是内部类或者是静态内部类
* metadata.isConcrete():不能是接口或抽象类
* metadata.isAbstract():是抽象类、
* metadata.hasAnnotatedMethods(Lookup.class.getName()):有lookUp注解标注
* 总结就是需要满足以下两个条件:
* 1. 不能是内部类或者是静态内部类
* 2. 不能是接口或者抽象类,如果是抽象类,则需要LookUp注解标注
*/
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
至此,自定义标签的解析就已经完成了。