想要搞清楚springboot是怎么实现自动配置的,就要知道springboot程序是在哪里开始运行的,我们在运行springboot程序的时候只需要运行main方法就行,这个类头上只有一个@SpringbootApplication注解,我们就搞清楚这一个注解的作用就行。
按住CTRL键,点开这个注解,如下所示:
里面核心的注解有三个
@SpringbootConfiguration,@EnableAutoConfiguration, @ComponentScan,我们只需要搞懂这三个注解的作用就行。
1.@SpringbootConfiguration
我们点进去一探究竟
里面的核心注解就是@Configuration这个注解,大家可能一看就明白了,这个注解就是一个标明配置类的注解,只不过这里将它包装成了@SpringbootConfiguration这个注解。搞定一个,让我们接着往下看。
2.EnableAutoConfiguration
我们依旧是点进去看看这是个啥
这里面有两个核心的注解
@AutoConfigurationPackage,@Import({AutoConfigurationImportSelector.class })。那我们只需要搞清楚这两个东西的作用就行。
2.1.@AutoConfigurationPackage
继续点进去看看
这里面就只有一个核心的注解
2.1.1.@Import({AutoConfigurationPackages.Registrar.class})
我们看看他做了一些什么事,点开Registrar
在这里打个断点调试一下,AnnotationMetadata字面意思就是注解的元数据,这个东西的值就是我们主类的路径,在我这里就是com.example.SpringbootStartApplication, BeanDefinitionRegistry字面意思就是bean定义注册器,用来注册bean的。下面调用register方法的时候将它传了进来,将后面的参数选中计算出来是com.example,将我们的包传了进去,相当于指定了扫描包路径的位置。
让我们再点register方法进去看看
再点开BasePackageBeanDefinition
这里就相当于定义了一个bean,bean的名称就是这个类的全路径类名(绿色那行小字),然后将我们传进来的包名给他加进去。
其实这里主要是干了什么呢,其实简单来说就是你要扫描哪些包,Springboot总得知道才行,就通过这种方式告诉Springboot要扫描哪些包,在这里来说就是要扫com.example下面的包。
2.2.@Import({AutoConfigurationImportSelector.class})
老规矩点开看看
可以看到这个类实现了很多接口,这里主要看的是DeferredImportSelector接口,里面有一个方法process是我们主要需要研究的,我们在这个类里搜一下这个方法
里面调用了一个方法的名称叫getAutoConfigurationEntry,字面意思就是获得自动配置的入口,我们点开这个方法
这里有个方法叫getCandidateConfigurations,字面意思就是获取候选的配置,返回一个list集合,感觉这与我们的目的地越来越近了,继续点开这个方法。
这里有一个小细节,在springboot2.7版本之前呢,是采用loadFactoryNames方法来加载自动配置的,但在springboot2.7版本之后呢,就是用load方法来加载自动配置。
2.7版本之前:
我们点开loadFactoryNames这个方法
继续点开loadSpringFactories
截取了一部分出来,如下:
这里字面意思就是类加载器去"META-INF/spring.factories"这个目录下获取资源,并将获取的资源依次读取出来。
2.7版本之后:
这里有个方法叫load,继续点进去查看
这里最重要的就是这个文件==>“META-INF/spring/%s.imports”,我们去找一下这个文件
在左边项目的外部库中找到
这个文件里装的就是spring一些常用的技术,下面截取了一些给大家看看
下面还有很多,这些类都存放在这个文件里,当项目启动的时候,这些技术集合的配置全被加载到了内存中。供后续需要使用的时候用。
小总结:
1.在springboot2.7版本之前是通过读取META-INF/spring.factories文件来加载自动配置的
2.在springboot2.7版本之后是通过读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports这个文件来加载自动配置的。
3.@ComponentScan
其实顾名思义,这个注解就是扫描声明了@Component注解的类
这个注解会默认扫描该类所在的包下所有的加了@Component注解的类,当然包括其衍生的注解@Service,@Controller,@Repository,相当于之前的<context:component-scan>,然后将其扫描到的类注入到spring容器中,成为bean。
讲完了这些注解,那么springboot又是怎么实现,只需要导入相应技术的坐标就可以使用这些技术的呢。
我们随便找一个技术,我就拿kafka举例
我们在项目里搜索这个类(双击shift键,将上面选中的这串类名复制粘贴进去) 如下所示:
双击打开它 ,如下所示:
这个自动配置类上面加了一个ConditionalOnClass的注解,Conditional系列注解的作用就是用来判断条件的,这里的作用就是判断KafkaTemplate这个类在不在当前的环境中, 如果在, 就把kafkaAutoConfiguration这个自动配置类加载进来, 我们进KafkaTemplate这个类中看,发现他是在kafka的核心包下的,那么一切就豁然开朗了,我们在需要使用kafka技术的时候,导入相对应的坐标,那么其中肯定包含kafka的核心包,也就是kafkaTemplate这个类会被加载进来,既然如此,KafkaAutoConfiguration这个自动配置类也就顺理成章的加载了进来,这样就可以使用相对应的技术了。
这也正是springboot优雅的地方,它将很多常用的技术列了出来,在项目加载的时候一起加载进来,但我们可以根据自己的需要添加相对应的坐标,而只有我们需要的技术才会被会真正加载进来,得以使用相对应的技术。
以上就是springboot自动配置的原理,希望能帮到大家,如果当中有什么讲错的地方,请私信我,指出我的错误,谢谢大家。