SpringBoot自动加载

SpringBoot自动装配

Spring的自动装配机制简单来说就是将各种需要的Bean装配进框架容器中。

SpringBoot自动装配分为两类:

  1. 自动装配本项目Bean
  2. 自动装配依赖jar包下提供的bean

一起来看下SpringBoot是怎样加载的。很显然,SpringBoot项目是从main方法开始启动的,这个方法中做了什么呢?

SpringBoot自动加载_第1张图片

在这里可以看到Spring将自身类加载进了容器中,这里跟spring加载配置类进容器一样。至于为什么加载这个类进容器就会自动装配好所有需要的bean信息,就是下面要说的。重点对象就是@SpringBootApplication。

我们来进入@SpringBootApplication看一下里面做了什么。

SpringBoot自动加载_第2张图片

这里面重点对象包含三个:

@SpringBootConfiguration

SpringBoot自动加载_第3张图片

@EnableAutoConfiguration

SpringBoot自动加载_第4张图片

@ComponentScan

先来说一下@SpringBootConfiguration,@SpringBootConfiguration中包含了@Configuration,也就是说run()方法加载进去的是一个配置类,配置类中是可以对其他bean进行配置的。这就让这个启动类有了加载bean的权限。

而@ComponentScan就是将包下的所有Bean加载进容器,在这里就是将这个类所在的包下所有bean加载进容器。

所以为什么启动类一定要在项目根包下就不难理解了。这里加载的是本项目的bean。

看@EnableAutoConfiguration之前,我们先来看一下@Import注解的玩法

@Import也将bean加载进容器的注解,不同的是这个注解有三种加载方式,可以变着姿势对bean进行加载。只要思想不滑坡。

[@Import加载bean的三种方法:]((60条消息) @Import注解的作用_一直打铁的博客-CSDN博客_@import)

  1. 导入普通类

    @Import({TestA.class})
    @Configuration
    public class ImportConfig {
    }
    
  2. 导入一个实现了DeferredImportSelector接口的类

    实现了ImportSelector接口的类会重写一个selectImports,这个方法会将返回的字符串数组中的bean加载进容器(重点)。这是唯一一种可以批量加载bean的。

    @Import({SelfImportSelector.class})
    @Configuration
    public class ImportConfig {
    }
    
    public class SelfImportSelector implements ImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[]{"com.test.importdemo.TestC"};
        }
    }
    
    
  3. 导入一个实现了ImportBeanDefinitionRegistrar接口的类

    这个类会重写registerBeanDefinitions方法,在这个方法中可以对类进行加载

    @Import({SelfImportBeanDefinitionRegistrar.class})
    @Configuration
    public class ImportConfig {
    }
    
    public class SelfImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            RootBeanDefinition root = new RootBeanDefinition(TestD.class);
            registry.registerBeanDefinition("testD", root);
        }
    }
    

了解完@Import的用法,让我们再回到@EnableAutoConfiguration注解中。

![image-20220423145432134](https://ling-28.oss-cn-beijing.aliyuncs.com/img/image-20220423145432134.png

@EnableAutoConfiguration中的注解@Import加载了一个AutoConfigurationImportSelector.class,让我们看一下这个类做了什么。从里面我看到了这个方法。很显然是用了@Import的第二种方法进行加载bean。具体加载了什么bean呢,再深入探探。

@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

这是getAutoConfigurationEntry方法的具体实现:

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
    	//从jar包中加载class
    	// 这里获取class是从classpath下的jar包中的META-INF/spring.factories中读取到的
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
   		//过滤掉重复的class文件 
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

依赖的jar包中有会在META-INF下包含spring.factories文件

image-20220423171730309

在自动加载流程中会把EnableAutoConfiguration作为key,下面的class会以“,”隔开作为值,进行读取加载。注:这些class大多都会是jar包中提供给你的Configuration文件,Configuration中会给你提供对外的bean。你导入依赖后能调用的bean就是从这里来的。
菜鸟一个,错误的地方还望指出,拓展的知识希望大佬能跟我讲解一下。

你可能感兴趣的:(java,spring,boot,java,spring)