本文共 7277 字,大约阅读时间需要 24 分钟。
父依赖
其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件!org.springframework.boot spring-boot-starter-parent 2.3.4.RELEASE
点进去,发现还有一个父依赖
org.springframework.boot spring-boot-dependencies 2.3.4.RELEASE
这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;
以后我们导入依赖默认是不需要写版本;但是如果导入的包没有在依赖中管理着就需要手动配置版本 了;org.springframework.boot spring-boot-starter-web
springboot-boot-starter-xxx:就是spring-boot的场景启动器
spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件;SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些 starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我 们未来也可以自己自定义 starter
默认的主启动类
package com.loey;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;//SpringBoot项目启动入口类@SpringBootApplication//springboot核心注解,主要用于开启spring自动配置public class Application { //springboot项目代码必须放到Application类所在的同级目录或下级目录 public static void main(String[] args) { //以为是启动了一个方法,没想到启动了一个服务 SpringApplication.run(Application.class, args); }}
作用: 标注在某个类上说明这个类是SpringBoot的主配置类 , SpringBoot就应该运行这个类的main方 法来启动SpringBoot应用;
进入这个注解:可以看到上面还有很多其他注解
@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 { //.....}
这个注解在Spring中很重要 ,它对应XML配置中的元素。
作用: 自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中
作用: SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类;
我们继续进去这个注解查看
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Configurationpublic @interface SpringBootConfiguration { //....}
点进去:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface Configuration { //....}
这里的 @Configuration,说明这是一个配置类 ,配置类就是对应Spring的xml 配置文件;
里面的 @Component 这就说明,启动类本身也是Spring中的一个组件而已,负责启动应用! 我们回到 SpringBootApplication 注解中继续看@EnableAutoConfiguration : 开启自动配置功能
以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置 ; @EnableAutoConfiguration 告诉SpringBoot开启自动配置功能,这样自动配置才能生效;
点进注解接续查看:@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration { //...}
@AutoConfigurationPackage : 自动配置包
点进去查看@Import(AutoConfigurationPackages.Registrar.class)public @interface AutoConfigurationPackage { //....}
@import :Spring底层注解@import , 给容器中导入一个组件
Registrar.class 作用: 将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器 ;这个分析完了,退到上一步,继续看
@Import({AutoConfigurationImportSelector.class}) :给容器导入组件 ; AutoConfigurationImportSelector : 自动配置导入选择器,那么它会导入哪些组件的选择器呢? 我们 点击去这个类看源码:1、这个类中有一个这样的方法
// 获得候选的配置protected ListgetCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { //这里的getSpringFactoriesLoaderFactoryClass()方法 //返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration List 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; }
2、这个方法又调用了 SpringFactoriesLoader 类的静态方法!我们进入SpringFactoriesLoader类 loadFactoryNames() 方法
public static ListloadFactoryNames(Class factoryType, @Nullable ClassLoader classLoader) { String factoryTypeName = factoryType.getName(); //这里它又调用了 loadSpringFactories 方 return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); }
3、我们继续点击查看 loadSpringFactories 方法
private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) { //获得classLoader , 我们返回可以看到这里得到的就是EnableAutoConfiguration标注 的类本身 MultiValueMap result = cache.get(classLoader); if (result != null) { return result; } try { //去获取一个资源 "META-INF/spring.factories" Enumeration urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); //将读取到的资源遍历,封装成为一个Properties while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry entry : properties.entrySet()) { String factoryTypeName = ((String) entry.getKey()).trim(); for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryTypeName, factoryImplementationName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }
4、发现一个多次出现的文件: spring.factories ,全局搜索它
我们根据源头打开spring.factories , 看到了很多自动配置的文件;这就是自动配置根源所在!
WebMvcAutoConfiguration
我们在上面的自动配置类随便找一个打开看看,比如 : WebMvcAutoConfiguration 可以看到这些一个个的都是JavaConfig配置类,而且都注入了一些Bean,可以找一些自己认识的类,看 着熟悉一下! 所以,自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件 ,并将其中 对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IOC容器配置类 , 然后将这些都汇总成为一个实例并加载到IOC容 器中不简单的方法,开启了一个服务
//SpringBoot项目启动入口类@SpringBootApplication//springboot核心注解,主要用于开启spring自动配置public class Application { //springboot项目代码必须放到Application类所在的同级目录或下级目录 public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
SpringApplication.run分析 ,分析该方法主要分两部分,
SpringApplication
这个类主要做了以下四件事情: 1、推断应用的类型是普通的项目还是Web项目 2、查找并加载所有可用初始化器 , 设置到initializers属性中 3、找出所有的应用程序监听器,设置到listeners属性中 4、推断并设置main方法的定义类,找到运行的主类查看构造器
public SpringApplication(ResourceLoader resourceLoader, Class ... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
run方法
转载地址:http://sluki.baihongyu.com/