1.自动配置
(1).pom.xml
在pom文件中
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
在它的父工程中,有他的核心依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
点进去,我们发现,springboot自动帮我们管理了依赖
这只是其中的一小部分,我们在写或者引入有一些依赖的时候,不需要指定版本
(2).启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
springboot-boot-starter:就是spring-boot的场景启动器
这里的 spring-boot-starter-web 帮我们导入了web模块正常运行所依赖的组件;
SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;
(3).主程序(启动类)
package com.bao;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Springboot01HelloworldApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot01HelloworldApplication.class, args);
}
}
@SpringBootApplication 来标注一个主程序类 , 说明这是一个Spring Boot应用
run方法: 将Spring应用启动起来
我们看一下@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) })
public @interface SpringBootApplication {
......略
}
- @SpringBootConfiguration :SpringBoot的配置类 ,标注在某个类上,表示这是一个SpringBoot的配置类
- @EnableAutoConfiguration : 启用自动配置,这个注解是让Spring Boot配置能够如此简化的关键性注解
- @ComponentScan : 扫描当前主启动类同级的包
点击@SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
}
@Configuration : 代表是一个spring配置类
点击
Configuration
发现有一个@Component,代表是一个spring组件
点击@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
主要是 :
- @AutoConfigurationPackage
- @Import(AutoConfigurationImportSelector.class)两个
AutoConfigurationPackage(自动配置包)
注解的作用是将 添加该注解的类所在的package 作为 自动配置package 进行管理。
主要是Registrar.class
package org.springframework.boot.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//导入选择器
@Import(AutoConfigurationPackages(自动配置注册包).Registrar.class)
public @interface AutoConfigurationPackage {
}
@import :Spring底层注解@import , 给容器中导入一个组件 ,导入的组件由 {Registrar.class} 将主配置类 【即@SpringBootApplication标注的类】的所在包及包下面所有子包里面的所有组件扫描到Spring容器 ;
@Import(AutoConfigurationImportSelector.class)
- Import他的作用是给容器导入组件
- AutoConfigurationImportSelector.class: (自动配置导入选择器)导入哪些组件的选择器
它将所有需要导入的组件以全类名的方式返回 , 这些组件就会被添加到容器中 ;
它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;
有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;
点击AutoConfigurationImportSelector
有这样的一个方法
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:获取候选配置
//获取所有配置
List<String> configurations =
getCandidateConfigurations(annotationMetadata, attributes);
点击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;
}
//返回用来加载配置候选的类。标注了EnableAutoConfiguration注解的类(主启动类)
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
而在
@SpringBootApplication
注解中标注了@EnableAutoConfiguration所以就是启动类下的所有资源被导入
在这里我们发现了META-INF/spring.factories文件.这个就是自动配置的核心文件
我们去springboot的jar中寻找该文件
List<String> configurations = SpringFactoriesLoader.loadFactoryNames
(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());
点击loadFactoryNames
方法
loadFactoryNames : 获取所有的加载配置
返回的loadSpringFactories
从这些资源中便利了所有的nextElement元素(也可以理解为自动配置)
遍历完成后封装成Properties,供我们使用
//所有资源加载到配置类中
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
获取项目资源:classLoader.getResources(FACTORIES_RESOURCE_LOCATION)
获取系统资源:ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION))
点击FACTORIES_RESOURCE_LOCATION
,获取静态资源的位置
从META-INF/spring.factories获取配置文件
需要导入对应的starter才能起作用
例如
由于@ConditionalOnClass
的存在,会判断条件成立,才会加载配置这个类
@ConditionalOnXXX
如果这里面的条件都满足,才会生效
(4).结论
SpringBoot所有的自动配置都在启动类中扫描并加载,也就是spring.factories
文件
所有的自动配置类都在这个文件中,但是并不一定生效,要判断条件是否成立,只要导入对应的start,就会有对应的启动器,有了启动器,自动装配就会生效,然后就配置成功了
1.springboot在启动的时候,会从类路径下META-INF/spring.factories
文件中获取指定的值
2.将这些自动配置的类导入容器,自动配置类就会生效,帮我们进行自动配置
3.springboot帮我们做了我们以前需要的配置.
4.整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
5.他会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器
6.容器中也会存在非常多的XxxAutoConfiguration的文件(@Bean),就是这些类给容器中导入了这个场景所需要的所有组件
7.有了自动配置类,就不需要写配置文件
我们找一个打开看看 : WebMvcAutoConfiguration
所以,真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IOC容器配置类 , 然后将这些都汇总成为一个实例并加载到IOC容器中。
2.Run
@SpringBootApplication
public class SpringbootDemo02Application {
public static void main(String[] args) {
//该方法返回一个ConfigurableApplicationContext对象
//参数一:应用入口的类 参数类:命令行参数
SpringApplication.run(SpringbootDemo02Application.class, args);
}
}
SpringApplication.run分析
分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行;
SpringApplication的实例化
1.推断应用的类型是普通的项目还是Web项目
2.查找并加载所有可用初始化器 , 设置到initializers属性中
3.找出所有的应用程序监听器,设置到listeners属性中
4.推断并设置main方法的定义类,找到运行的主类
3.谈谈你对springboot的理解
- 自动装配
- run方法
每个优秀的人,都有一段沉默的时光.那段时光,是付出很多努力,却得不到结果的日子,我们把他叫做扎根