一、入口
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是什么时间被加载的