个人博客:haichenyi.com。感谢关注
上一篇,内容很少,说了一下SpringBoot的底层是怎么依赖的。这一篇讲一下SpringBoot底层源码是怎么实现的。
从SpringBoot的入口开始。第一篇的时候说过了,最好把入口文件放在最外层的包下面,至于原因就不多阐述了。
说说这个 @SpringBootApplication注解的原理,点进去看一下:
如下图:
主要就是这三个注解:
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
@SpringBootConfiguration
SpringBootConfiguration这个注解是由Configuration注解实现的。
@Configuration
从名字上就可以判断出,这个注解是跟SpringBoot配置相关的,@Configuration,这个注解是Spring底层的一个注解,之前都是配置xml,SpringBoot推荐我们用配置类来描述配置,配置类是什么呢?就用@Configuration标记的类。
Configuration这个注解是由Component注解实现。
@Component
这个注解的意义就是,把当前的配置类添加到spring容器中,表示是一个组件。
@EnableAutoConfiguration
EnableAutoConfiguration这个注解是由AutoConfigurationPackage和**@Import({AutoConfigurationImportSelector.class})**注解实现
@AutoConfigurationPackage
这个注解从名字上面看出来是自动配置包,这是什么意思呢?在第一篇我们就说过了入口要放在最外层的包,至于原因,已经讲过了,因为SpringBoot会自动将引导类 @SpringBootApplication标注的类所在的包以及下面所有子包里面所有的组件扫描到Spring容器中统一管理。就是这个注解实现的。那么,这个注解是怎么实现的呢?就是通过它的这个 @Import({Registrar.class}),下面就是Registrar类的源码了
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
}
就是通过下面这个代码注册进去的。
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
@Import({AutoConfigurationImportSelector.class})
这个注解是干什么用的呢?
- 它会把项目里面所有需要导入的组件以全类名的方式返回,将这些组件添加到容器中。
- 会给容器中注入非常多的自动配置类,就是导入并配置好当前项目中
所需要的组件,省去我们手动编写配置去注入组件。
怎么实现的呢?打开AutoConfigurationImportSelector类,找到如下代码:
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
找到getCandidateConfigurations方法,如下:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
找到loadFactoryNames方法,如下:
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
找到loadSpringFactories方法,里面有
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
这里就是我们的配置,我们这个配置具体是在哪呢?如下图
@ComponentScan
这个注解的主要作用就是,被该注解标识的类会被Spring容器纳入管理。