一、入口
Springboot中@Configuration注解被扫描到的入口在AbstractApplicationContext类中的
invokeBeanFactoryPostProcessors(beanFactory)
;
方法中,方法上面有一行注解为
// Invoke factory processors registered as beans in the context.意思是把处理beanFactory的程序类型注册为Context中的bean。
// Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory);
这句话的意思是spring-boot启动添加不由容器管理的BeanFactoryPostProcessor,实例化后直接保存在AbstractApplicationContext.beanFactoryPostProcessors。BeanFactoryPostProcessor包括以下
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer$
ConfigurationWarningsPostProcessor
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer$
CachingMetadataReaderFactoryPostProcessor
org.springframework.boot.context.config.ConfigFileApplicationListener$
PropertySourceOrderingPostProcessor
2、BeanFactoryPostProcessors
在后面的invokeBeanFactoryPostProcessor()方法中,有两个参数beanFactory和和beanFactoryPostProcessors。在beanFactoryPostProcessors中存在三个beanFactoryPostProcessor,分别是
1、ConfigurationWarningsApplicationContextInitializer$ConfigurationWarningsPostProcessor
这个类的作用是查看@ComponentScan扫描的包有没有问题,有的话则进行打印,在Spring-boot中这个类基本使用不到了,因为在@
SpringBootApplication注解中包含了
@ComponentScan
(、
@SpringBootConfiguration、
@SpringBootConfiguration注解,所以这个类就不起作用了
2、
SharedMetadataReaderFactoryContextInitializer$
CachingMetadataReaderFactoryPostProcessor
3、
ConfigFileApplicationListener$
PropertySourceOrderingPostProcessor
然后去beanFactory中取出一个
BeanDefinitionRegistryPostProcessor类型的beanConfigurationClassPostProcessor,与beanfactory一起进入了方法
invokeBeanDefinitionRegistryPostProcessors
(currentRegistryProcessors
,
registry)
;
3、ConfigurationClassPostProcessor
上次放我们说
invokeBeanDefinitionRegistryPostProcessors
(currentRegistryProcessors
,
registry)
;方法中传入了两个参数一个是ConfigurationClassPostProcessor,一个是BeanFactory,那么我们看下ConfigurationClassPostProcessor类,解析@Configuration注解的入口方法:processConfigBeanDefinitions,入参是beanFactory
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); String[] candidateNames = registry.getBeanDefinitionNames(); for (String beanName : candidateNames) { BeanDefinition beanDef = registry.getBeanDefinition(beanName); if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) { if (logger.isDebugEnabled()) { logger.debug("Bean definition has already been processed as a configuration class: " + beanDef); } } else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) { configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); } }
首先是获取beanFactory中加载的所有BeanDefinition:String[] candidateNames = registry.getBeanDefinitionNames();
然后遍历操作,将我们项目启动的入口bean,Applicaition类放入到
configCandidates集合中。
最后一Application类作为参数传入到
ConfigurationClassParser类的parse()方法中。
// Process any @ComponentScan annotations Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { for (AnnotationAttributes componentScan : componentScans) { // The config class is annotated with @ComponentScan -> perform the scan immediately Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
然后在ConfigurationClassParser类中的
componentScanParser的parse方法,对@Component注解的**/*.class,即当前Application同级目录下的类,进行扫描
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)) {
4、@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
上面的注解是在SpringBootApplication中的注解,意思是Spring扫描的包中排除的类,其中
TypeExcludeFilter.class是排除特定类型的bean加入,
AutoConfigurationExcludeFilter.class意思是,如果你自己声明了一个DubboConfiguration然后也用pom文件中配置了spring-dubbo-start启用了带有@AutoConfiguration注解的bean,那么会忽略你自己写的bean,但前提是,两个@Configuration的类的名称要一模一样,否则不起作用