Springboot@Configuration注解被扫面注射为bean的源码解析(一)

版权声明:本博文是原创作品,转载请注明出处 https://blog.csdn.net/lz710117239/article/details/80692023

一、入口

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





阅读更多

没有更多推荐了,返回首页