context:component-scan 标签解析
来源:互联网 发布:林向正手抛网淘宝价格 编辑:程序博客网 时间:2024/05/21 09:50
1.作用
扫描classpath下带有注解的类,注册成spring bean。Spring 默认提供的注解包括@Component,@Repository,
@Service,@Controller,@RestController,@ControllerAdvice, @Configuration。
它有一个annotation-config属性默认是ture,它的作用和<context:annotation-config /> 一样。激活@Required,@Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext ,@PersistenceUnit注解
@Overridepublic BeanDefinition parse(Element element, ParserContext parserContext) { String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE); basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage); String[] basePackages = StringUtils.tokenizeToStringArray(basePackage, 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;}我们看扫描完成后,有一个注册组件的方法registerComponents(),我们看这个方法
// 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)); }}这句代码就是处理@Required,@Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext ,@PersistenceUnit相关注解
Set<BeanDefinitionHolder> processorDefinitions = AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);我们看annotation-config 标签的解析器代码,有同样的一段代码。
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
public class AnnotationConfigBeanDefinitionParser implements BeanDefinitionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { Object source = parserContext.extractSource(element); // Obtain bean definitions for all relevant BeanPostProcessors. Set<BeanDefinitionHolder> processorDefinitions = AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source); // Register component for the surrounding <context:annotation-config> element. CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source); parserContext.pushContainingComponent(compDefinition); // Nest the concrete beans in the surrounding component. for (BeanDefinitionHolder processorDefinition : processorDefinitions) { parserContext.registerComponent(new BeanComponentDefinition(processorDefinition)); } // Finally register the composite component. parserContext.popAndRegisterContainingComponent(); return null; }}
所以当我们有context:component-scan标签时,可以省略annotation-config 标签了。
2.流程
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);主要是创建ClassPathBeanDefinitionScanner对象然后扫描指定的包路径。
ClassPathBeanDefinitionScanner scanner = createScanner(readerContext, useDefaultFilters);
protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) { return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters);}
我们看创建ClassPathBeanDefinitionScanner源代码有下面一句
public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment) { if (useDefaultFilters) { registerDefaultFilters(); } this.environment = environment;}
protected void registerDefaultFilters() { 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.debug("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.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning"); } catch (ClassNotFoundException ex) { // JSR-330 API not available - simply skip. }}默认扫描Component注解。实际上@Repository,@Service,@Controller,@RestController,@ControllerAdvice, @Configuration。上面都是有Component注解。
我们看扫描指定包的方法
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;}通过扫描包下面的每一个Class(findCandidateComponents方法),读取信息看是否匹配
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);if (isCandidateComponent(metadataReader))我们看一下怎么算匹配,首先看是否match,然后判断Profile注解指定的值
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { for (TypeFilter tf : this.excludeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { return false; } } for (TypeFilter tf : this.includeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); if (!metadata.isAnnotated(Profile.class.getName())) { return true; } AnnotationAttributes profile = MetadataUtils.attributesFor(metadata, Profile.class); return this.environment.acceptsProfiles(profile.getStringArray("value")); } } return false;}我们看match方法
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { // This method optimizes avoiding unnecessary creation of ClassReaders // as well as visiting over those readers. if (matchSelf(metadataReader)) { return true; }
AnnotationTypeFilter实现了matchSelf方法,即匹配是否有注解Component。
@Overrideprotected boolean matchSelf(MetadataReader metadataReader) { AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); return metadata.hasAnnotation(this.annotationType.getName()) || (this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));}
阅读全文
0 0
- context:component-scan 标签解析
- spring <context:component-scan>标签
- Spring的 <context:component-scan>标签
- context:component-scan标签的use-default-
- spring context:component-scan标签实现原理
- Spring标签<context:component-scan>的用法
- context:component-scan
- spring - context:component-scan
- spring context:component-scan
- <context:component-scan>使用说明
- <context:component-scan>使用说明
- <context:component-scan>使用说明
- <context:component-scan>使用说明
- <context:component-scan>使用说明
- context:component-scan
- <context:component-scan>使用说明
- <context:component-scan>使用说明
- <context:component-scan>使用说明
- centos7 安装apache教程以及安装后无法访问的原因以及解决方案
- SpringBoot项目取消数据库配置
- 如何让eacharts 堆叠图不堆叠
- LUOGU P1843 奶牛晒衣服
- 论文笔记:Self-critical Sequence Training for Image Captioning
- context:component-scan 标签解析
- XSS网站攻击演示
- shell bash常用的相关命令快捷建--字符串分割, 光标移到行首、行尾等
- eclipse安装JAVA反编译插件
- 1016. 部分A+B (15)——C语言
- Android之自定义一个可播放某一时间段的音乐播放器
- Hadoop伪分布式环境配置
- 刷LeetCode(5)——Longest Palindromic Substring
- log4j常用日志配置