Springboot—学习过程—Springboot的自动装配原理探索
1.通过POM文件可以看到什么
-
它是依赖一个父项目,主要是管理项目的资源过滤及插件!
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>
资源过滤:
插件:(飘红的见笑了,看一下就好,嘿嘿)
-
点击
spring-boot-starter-parent
发现里面还有一个父依赖<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.2.5.RELEASE</version> <relativePath>../../spring-boot-dependencies</relativePath> </parent>
spring-boot-dependencies
才是真正管理SpringBoot应用里面所有依赖版本的地方,是SpringBoot的版本控制中心,里面全是版本信息;以后我们导入依赖默认是不需要写版本;如果导入的包没有在依赖中管理着就需要手动配置版本了;- 所以说我们在引入springboot的版本依赖的时候不需要指定版本,因为有这些版本仓库
2.通过POM文件中的启动器看
启动器
:springboot-boot-starter-xxx,就是springboot的xxx启动场景
举个例子:<!--启动器--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
spring-boot-starter-web
启动器就会帮我们自动导入web环境所有的依赖
注: SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义 starter;<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
3.通过主启动类看
- 查看表面
- 通过
@SpringBootApplication
注解标注一个主程序类,说明这是一个Spring Boot应用
//通过 @SpringBootApplication 注解标注一个主程序类,说明这是一个Spring Boot应用,而且继承了@EnableAutoConfiguration所以是启动类下的所有资源都被导入 @SpringBootApplication public class SpringbootApplication { public static void main(String[] args) { //以为是启动了一个方法,其实是启动了一个服务,将springboot应用启动 SpringApplication.run(SpringbootApplication.class, args); } }
- 通过
- 查看注解
-
点击
@SpringBootApplication
注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
上面四个是源注解
@SpringBootConfiguration
@EnableAutoConfiguration
上面两个一会儿看看
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class}), @Filter(
type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} ) } )
这个是扫描剔除包的
-
@SpringBootConfiguration
:Springboot
的配置类,标注在某个类上 , 表示这是一个SpringBoot
的配置类- 点击
@SpringBootConfiguration
注解发现里面有@Configuration
这个注解,表示是spring
的配置类@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { . . .}
- 点击
@Configuration
这个注解,发现里面还有一个注解@Component
,说明这也是Spring中的一个组件而已,启动类本身也是Spring中的一个组件而已,负责启动应用@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration { . . . }
- 点击
-
@EnableAutoConfiguration
:自动配置-
点击
@EnableAutoConfiguration
注解可以看到有一个注解@AutoConfigurationPackage
-
@AutoConfigurationPackage
是自动配置包
的意思,点击这个@AutoConfigurationPackage
注解后发现另一个注解@Import(AutoConfigurationPackages.Registrar.class)
导入“选择器”包注册器,之后查看AutoConfigurationPackages
的内容是一个类文件.java结尾的,作用是将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器 -
@Import(AutoConfigurationImportSelector.class)
注解,这个注解意思是:导入自动配置导入选择器
的类,点击AutoConfigurationImportSelector
这个类进去一看,可以看到导入了环境,资源加载器
//环境 private Environment environment; private ClassLoader beanClassLoader; //资源加载器 private ResourceLoader resourceLoader;
选择组件的方法:选择组件是干嘛的,是要选择配置在
pom.xml
文件中的东西,因为不导入进来就是用不了,所以真正选择的是pom.xml
文件中的组件public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader //loadMetadata表示加载源数据 .loadMetadata(this.beanClassLoader); AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }
顺着代码在下一个方法中:发现
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
是获取所有的配置protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }
之后点击查看 getCandidateConfigurations 方法 这个是获取候选配置的方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { //通过一个加载器加载所有的 List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), 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; }
之后点击查看 getBeanClassLoader 方法 ,beanClassLoader也是一个加载器
protected ClassLoader getBeanClassLoader() { return this.beanClassLoader; }
之后点击查看 getSpringFactoriesLoaderFactoryClass() 方法 ,他作为参数在
getBeanClassLoader()
方法前面,这个方法返回了EnableAutoConfiguration.class
,也就是EnableAutoConfiguration类的所有包和所有配置protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }
继续往下看有个Assert.notEmpty ,这是断言 非空的意思,其中有一个
META-INF/spring.factories
,这个是自动配置的核心文件,如下图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.");
点开spring.factories文件发现有好多配置
这时候在通过方法loadFactoryNames( )查找,点击这个方法public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { String factoryTypeName = factoryType.getName(); return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); }
loadFactoryNames
这个方法在SpringFactoriesLoader.class
这个类中,看第一个参数factoryType
了解到加载了一个类,是标注了@SpringbootAPPlication
这样的一个类
上图中://所有资源加载到配置类中 Properties properties = PropertiesLoaderUtils.loadProperties(resource);
-
-
结论:
-
SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
-
将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
-
整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
-
它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;
-
有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;
梳理过程的不完全截图,看起来估计费劲