一 解析类
ComponentScanBeanDefinitionParsercomponent-scan标签解析类
component-scan 兼容 annotation-config ,因此前者配置后,后者不用在配置
二 解析类作用
1、基本包的扫描
2、类型过滤器的配置
3、 annotation-config配置的兼容
4、 注解处理器BeanPostProcessor的注册
三 解析过程
解析标签 <context component-scan base-package="com.icbc.inc,com.icbc.chg">
1.package扫描,多个包之间可能,分割;也有可能;分割 分割后得到一个包数组
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
2.配置scanner configureScanner(parserContext, element);
配置过滤器 如果标签中有 use-default-filters属性 使用配置的过滤器,如果没有,则使用默认
1.使用默认过滤器,默认过滤器注册过程
ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
创建scanner new ClassPathBeanDefinitionScanner 在ClassPathBeanDefinitionScanner中,使用多态将默认的过滤器注册进去
ClassPathScanningCandidateComponentProvider#ClassPathScanningCandidateComponentProvider-->registerDefaultFilters 方法
与 Component 同包 有 Controller,Repository,Service
Controller上面有Component注解,说明Controller是Component的子标签,同理 爱他两个也是Component的子标签
所以 注册Component注解,同时 Controller,Repository,Service也被注册进去
2.自定义过滤器注册过程 parseTypeFilters
use-default-filters 属性如果为false 就会使用自定义过滤器,此方法就是为了解析自定义过滤器
<context:component-scan base-package="com.icbc.inc,com.icbc.chg" use-default-filters="false">
<context :include-filter type ="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-sca>
如果localName 是include-filter 创建过滤器 根据type返回不同的过滤器
type: annotation assignable aspectj regex custom
3.扫描 doScan
1.findCandidateComponents
1.扫描的肯定是class文件,配置文件中包配置肯定是以.配置,先将.替换成/
ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + "/" + this.resourcePattern;
2.扫描到具体某个class对象,将其封装成resource对象 ,resource对象有一个属性为InputSource 输入流
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
GenericApplicationContext#getResources-->this.resourceLoader).getResources(locationPattern)
PathMatchingResourcePatternResolver#getResources
3.每一个resource对象都会封装成MetadataReader对象,如果有component注解,创建ScannedGenericBeanDefinition对象,并加入到返回到的集合中
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
2.遍历返回的集合,如果是AnnotatedBeanDefinition类型,执行方法
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
1.解析bean的属性(懒加载等等)
AnnotationConfigUtils#processCommonDefinitionAnnotations-->processCommonDefinitionAnnotations
3.将一个个bean封装成BeanDefinitionHolder,注册,放到集合中返回
bean注册进map中,beanName加入到一个集合中,以后实例化用(DefaultListableBeanFactory实现的)
4.registerComponents
1.实现对annotation-config标签的兼容<component-scan annotation-config="true">
首先判断component-scan中是否配置了annotaion-config属性,值为配置的属性值
如果没有配置annotaion-config属性,直接为true
2.如果上述标志位为true
Set<BeanDefinitionHolder> processorDefinitions =
AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
此方法中实现了对@Autowired @Required @Resource注解的实现
AutowiredAnnotationBeanPostProcessor RequiredAnnotationBeanPostProcessor CommonAnnotationBeanPostProcessor
xml
优点:0侵入性,不用继承接口,在配置文件中,多有实例都会new出来
缺点:配置混乱,尤其是项目变大
annotation:
优点:简单使用
缺点:侵入性太强