本节会揭晓:
自定义标签解析流程和注册过程
重点:< context:component-scan > 的解析
正是由于对这个自定义标签的解析,Spring 有了@Component,@Lazy,@DependOn,@Primary,@Role,@Description,@PostConstruct,@PreDestroy,@Resource,@Autowired,@Value 的支持
前面的文章 Spring5 源码阅读笔记(1.1)obtainFreshBeanFactory() 末尾介绍到了默认标签解析和自定义标签解析。
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
//默认标签解析
parseDefaultElement(ele, delegate);
}
else {
//自定义标签解析
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
默认标签解析已经分析过了,见文章 Spring5 源码阅读笔记(1.1.1)parseDefaultElement(ele, delegate) 默认标签的解析和注册。
跟 parseCustomElement :
类 BeanDefinitionParserDelegate
跟 parseCustomElement :
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
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));
}
关于 NamespaceHandler 如果不了解,可以看这篇文章:从源码角度解读 xml 文件中的 xmlns、xsi、xsd
跟 parse :
类 NamespaceHandler
跟 parse :
类 BeanDefinitionParser
我们重点看 ComponentScanBeanDefinitionParser:
这个类对应< context:component-scan > 这个标签
/*
* 1、扫描路径。.class后缀的文件
* 2、要判断类上是否有注解 @Component
* 3、对于有注解的类,创建对应的 BeanDefinition
* 4、完成 BeanDefinition 注册
* 5、完成某些组件的注册
* */
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
//获取basePackage属性
String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
//可以用逗号分开
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
//重要程度 2 创建注解扫描器 就是这里面支持了@Component
// Actually scan for bean definitions and register them. 见1.1.2.1
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
//重要程度 5 扫描并把扫描的类封装成beanDefinition对象并注册 见1.1.2.2
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
//重要程度 5 注册 见1.1.2.3
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
1.1.2.1 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));
}
//创建注解的扫描器
// Delegate bean definition registration to scanner class.
ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());
if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {
scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
}
try {
parseBeanNameGenerator(element, scanner);
}
catch (Exception ex) {
parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
}
try {
parseScope(element, scanner);
}
catch (Exception ex) {
parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
}
parseTypeFilters(element, scanner, parserContext);
return scanner;
}
跟 createScanner:
protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters,
readerContext.getEnvironment(), readerContext.getResourceLoader());
}
跟 ClassPathBeanDefinitionScanner :
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
//使用默认的过滤器
if (useDefaultFilters) {
//@Component
registerDefaultFilters();
}
setEnvironment(environment);
setResourceLoader(resourceLoader);
}
跟 registerDefaultFilters :
类 ClassPathScanningCandidateComponentProvider,上面那个类的父类
protected void registerDefaultFilters() {
//注意这里,说明了要扫描的注解是 Component。具体的说是 includeFilters 里包含了 Component
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.trace("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 {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
1.1.2.2 doScan
类 ClassPathBeanDefinitionScanner
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) {
//扫描到有注解的类并封装成BeanDefinition对象
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) {
//支持了@Lazy @DependOn @Primary @Role @Description
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
//这里不看
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
//BeanDefinition 注册
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
可以看到这里和默认标签的 parseBeanDefinition 有点类似,核心是两步:
一、封装 BeanDefinition 对象
二、对 BeanDefinition 进行注册
第二步和前面默认标签的注册过程是一样的,就不跟代码了。主要看第一步:
跟 findCandidateComponents :
类 ClassPathScanningCandidateComponentProvider
跟 scanCandidateComponents :
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//这里递归寻找文件
Resource[] resources = getResourcePatternResolver().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 = getMetadataReaderFactory().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;
}
跟 isCandidateComponent :
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
//前面出现过的 includeFilters 这里又出现了,这里面就有 Component 注解
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
看完上面的源码,我们就可以知道了为什么加了 < context:component-scan base-package=""> 标签,spring 就会扫描包下的 @Component 注解。
下面这个方法可以放到后面看,会与1.4.2产生联系。
1.1.2.3 registerComponents
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) {
//注册了几个比较重要的BeanPostProcessor类
//ConfigurationClassPostProcessor,AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor
Set<BeanDefinitionHolder> processorDefinitions =
AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
}
}
readerContext.fireComponentRegistered(compositeDef);
}
跟 registerAnnotationConfigProcessors:
类 org.springframework.context.annotation.AnnotationConfigUtils
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable 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<>(8);
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));
}
// 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));
}
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));
}
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;
}
跟 registerPostProcessor:
private static BeanDefinitionHolder registerPostProcessor(
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//这个方法在1.1.1节已经看过了,这里就注册到了beanFactory中,
//这里并还没有注册到beanPostProcessors里,那一步是在1.3节里
registry.registerBeanDefinition(beanName, definition);
return new BeanDefinitionHolder(definition, beanName);
}
再回过头看一下ConfigurationClassPostProcessor,AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor 这三个类实现了什么:
它们都在 org.springframework.context.annotation 包下
ConfigurationClassPostProcessor:
见 Spring5 源码阅读笔记(2)AnnotationConfigApplicationContext 有更详细的介绍
AutowiredAnnotationBeanPostProcessor:
见 Spring5 源码阅读笔记(1.4.2.2)applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName) 有更详细的介绍
CommonAnnotationBeanPostProcessor :
注意这个 InstantiationAwareBeanPostProcessor,它会在 1.3 末尾出现,继而与 1.4.2.1 产生联系。
对注解的支持:
对 @Autowired @Value 的支持
对 @PostConstruct,@PreDestroy 的支持
对 @Resource 的支持见1.4.2.2
见 Spring5 源码阅读笔记(1.4.2.2)applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName) 有更详细的介绍