一、入口
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的类的名称要一模一样,否则不起作用
到这里只是说了Spring中怎么排除的bean,还没有讲到在什么地方加载的@Configuration注解,后面会接着开始说@Configuration'注解的bean是什么时间被加载的