概念:可以在咱们添加jar包依赖的时候,自动为咱们配置一些组件的相关配置,咱们无需配置或者只须要少许配置就能运行编写的项目java
问题:Spring Boot究竟是如何进行自动配置的,都把哪些组件进行了自动配置?spring
Spring Boot应用的启动入口是@SpringBootApplication注解标注类中的main()方法, @SpringBootApplication可以扫描Spring组件并自动配置Spring Boot springboot
下面,查看@SpringBootApplication内部源码进行分析 ,核心代码具体以下框架
@SpringBootApplication public class SpringbootDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringbootDemoApplication.class, args); } }
@Target({ElementType.TYPE}) //注解的适用范围,Type表示注解能够描述在类、接口、注解或枚举中 @Retention(RetentionPolicy.RUNTIME) //表示注解的生命周期,Runtime运行时 @Documented //表示注解能够记录在javadoc中 @Inherited //表示能够被子类继承该注解 @SpringBootConfiguration // 标明该类为配置类 @EnableAutoConfiguration // 启动自动配置功能 @ComponentScan( // 包扫描器 excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication { ... }
从上述源码能够看出,@SpringBootApplication注解是一个组合注解,前面 4 个是注解的元数据信息, 咱们主要看后面 3 个注解:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个核心注解,关于这三个核心注解的相关说明具体以下:工具
1.@SpringBootConfiguration注解源码分析
@SpringBootConfiguration注解表示Spring Boot配置类。查看@SpringBootConfiguration注解源码,核心代码具体以下。url
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration //配置IOC容器 public @interface SpringBootConfiguration { }
从上述源码能够看出,@SpringBootConfiguration注解内部有一个核心注解@Configuration,该注解是Spring框架提供的,表示当前类为一个配置类(XML配置文件的注解表现形式),并能够被组件扫描器扫描。因而可知,@SpringBootConfiguration注解的做用与@Configuration注解相同,都是标识一个能够被组件扫描器扫描的配置类,只不过@SpringBootConfiguration是被Spring Boot进行了从新封装命名而已 spa
2.@EnableAutoConfiguration注解code
@EnableAutoConfiguration注解表示开启自动配置功能,该注解是Spring
Boot框架最重要的注解,也是实现自动化配置的注解。一样,查看该注解内部查看源码信息,核心代码具体以下 对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0iesyK1X-1591594952790)(./images/image-20191226121755878.png)]
能够发现它是一个组合注解,Spring 中有不少以Enable开头的注解,其做用就是借助@Import来收集并注册特定场景相关的bean,并加载到IoC容器。@EnableAutoConfiguration就是借助@Import来收集全部符合自动配置条件的bean定义,并加载到IoC容器。
下面,对这两个核心注解分别讲解 :
(1)@AutoConfigurationPackage注解
查看@AutoConfigurationPackage注解内部源码信息,核心代码具体以下:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import({Registrar.class}) // 导入Registrar中注册的组件 public @interface AutoConfigurationPackage { }
从上述源码能够看出,@AutoConfigurationPackage注解的功能是由@Import注解实现的,它是spring框架的底层注解,它的做用就是给容器中导入某个组件类,例如@Import(AutoConfigurationPackages.Registrar.class),它就是将Registrar这个组件类导入到容器中,可查看Registrar类中registerBeanDefinitions方法,这个方法就是导入组件类的具体实现 :
从上述源码能够看出,在Registrar类中有一个registerBeanDefinitions()方法,使用Debug模式启动项目, 能够看到选中的部分就是com.lagou。也就是说,@AutoConfigurationPackage注解的主要做用就是将主程序类所在包及全部子包下的组件到扫描到spring容器中。
所以 在定义项目包结构时,要求定义的包结构很是规范,项目主程序启动类要定义在最外层的根目录位置,而后在根目录位置内部创建子包和类进行业务开发,这样才可以保证定义的类可以被组件扫描器扫描
(2)@Import({AutoConfigurationImportSelector.class}):将AutoConfigurationImportSelector这个类导入到spring容器中,AutoConfigurationImportSelector能够帮助springboot应用将全部符合条件的@Configuration配置都加载到当前SpringBoot建立并使用的IoC容器(ApplicationContext)中
继续研究AutoConfigurationImportSelector这个类,经过源码分析这个类中是经过selectImports这个方法告诉springboot都须要导入那些组件:
[
深刻研究loadMetadata方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LudWoPn0-1591594952801)(./images/image-20200119172325325.png)]
深刻getCandidateConfigurations方法
个方法中有一个重要方法loadFactoryNames,这个方法是让SpringFactoryLoader去加载一些组件的名字。
继续点开loadFactory方法
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { //获取出入的键 String factoryClassName = factoryClass.getName(); return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader); if (result != null) { return result; } else { try { //若是类加载器不为null,则加载类路径下spring.factories文件,将其中设置的配置类的全路径信息封装 为Enumeration类对象 Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); LinkedMultiValueMap result = new LinkedMultiValueMap(); //循环Enumeration类对象,根据相应的节点信息生成Properties对象,经过传入的键获取值,在将值切割为一个个小的字符串转化为Array,方法result集合中 while(urls.hasMoreElements()) { URL url = (URL)urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); Iterator var6 = properties.entrySet().iterator(); while(var6.hasNext()) { Entry<?, ?> entry = (Entry)var6.next(); String factoryClassName = ((String)entry.getKey()).trim(); String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); int var10 = var9.length; for(int var11 = 0; var11 < var10; ++var11) { String factoryName = var9[var11]; result.add(factoryClassName, factoryName.trim()); } } } cache.put(classLoader, result); return result;
会去读取一个 sprin g.factories 的文件,读取不到会表这个错误,咱们继续根据会看到,最终路径的长这样,而这个是spring提供的一个工具类
public final class SpringFactoriesLoader { public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; }
它实际上是去加载一个外部的文件,而这文件是在
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jxnhPKHT-1591594952805)(./images/image-20191226162644636.png)]
@EnableAutoConfiguration就是从classpath中搜寻META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项经过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的配置类,并加载到IOC容器中
以刚刚的项目为例,在项目中加入了Web环境依赖启动器,对应的WebMvcAutoConfiguration自动配置类就会生效,打开该自动配置类会发现,在该配置类中经过全注解配置类的方式对Spring MVC运行所需环境进行了默认配置,包括默认前缀、默认后缀、视图解析器、MVC校验器等。而这些自动配置类的本质是传统Spring MVC框架中对应的XML配置文件,只不过在Spring Boot中以自动配置类的形式进行了预先配置。所以,在Spring Boot项目中加入相关依赖启动器后,基本上不须要任何配置就能够运行程序,固然,咱们也能够对这些自动配置类中默认的配置进行更改
总结
所以springboot底层实现自动配置的步骤是:
5.
@Import(AutoConfigurationImportSelector.class):它经过将AutoConfigurationImportSelector类导入到容器中,AutoConfigurationImportSelector类做用是经过selectImports方法执行的过程当中,会使用内部工具类SpringFactoriesLoader,查找classpath上全部jar包中的META-INF/spring.factories进行加载,实现将配置类信息交给SpringFactory加载器进行一系列的容器建立过程
3. @ComponentScan注解
@ComponentScan注解具体扫描的包的根路径由Spring Boot项目主程序启动类所在包位置决定,在扫描过程当中由前面介绍的@AutoConfigurationPackage注解进行解析,从而获得Spring
Boot项目主程序启动类所在包的具体位置
总结:
@SpringBootApplication 的注解的功能就分析差很少了, 简单来讲就是 3 个注解的组合注解:
|- @SpringBootConfiguration |- @Configuration //经过javaConfig的方式来添加组件到IOC容器中 |- @EnableAutoConfiguration |- @AutoConfigurationPackage //自动配置包,与@ComponentScan扫描到的添加到IOC |- @Import(AutoConfigurationImportSelector.class) //到META-INF/spring.factories中定义的bean添加到IOC容器中 |- @ComponentScan //包扫描