继承springboot父工程依赖pox.xml

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.8.RELEASE</version></dependency>

spring-boot-starter-parent继承了spring-boot-dependencies

  • 这个依赖中定义了常用依赖的版本,以及锁定了其版本,所以我们在导入starter时,无需定义版本
  • 若没有在这里定义版本,则需要自己导入相应的版本信息,如mysql的jdbc驱动

starter【web】启动器

    <!-- 导入了web模块正常运行所依赖的组件,DispatcherServlet,内置tomcat容器等等--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>

spring-boot-starter-web:

    <!-- 这是springboot的基础依赖,基本所有的启动器都依赖于spring-boot-starter。其依赖内容包括自动配置,日志,注解,spring核心,yaml等。 导入了相应的starter后,springboot就会自动配置其运行组件springboot官方定义的启动器依赖都是以 spring-boot-starter 开头的。【spring-boot-starter-xxx】如果官方没有定义,其他技术需要集成springboot,则需要自己定义启动器依赖,如 mybatis 【mybatis-spring-boot-starter】--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.1.8.RELEASE</version><scope>compile</scope></dependency>

@SpringBootApplication注解

    // 标记当前是一个启动引导类,是springboot应用的入口。// 本身是一个组合注解。@SpringBootConfiguration // 点击@EnableAutoConfiguration // 点击// 包扫描器,不包含excludeFilters以下过滤注解@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM,classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {//...............}

@SpringBootConfiguration

    @Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Configuration //点击public @interface SpringBootConfiguration {}@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Component // 表示该注解是一个配置类注解,并且自己是容器中的一个组件public @interface Configuration {    @AliasFor(        annotation = Component.class    )    String value() default "";}

@EnableAutoConfiguration

    @Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage // 点击@Import({AutoConfigurationImportSelector.class})public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};}

@AutoConfigurationPackage

    @Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited// 自定义化配置包扫描,指定要扫描的包@Import({Registrar.class}) // 点击public @interface AutoConfigurationPackage {}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));}}private final String packageName;public String getPackageName() {// 包名:就是Spring容器需要去扫描能够识别的注解。其实就是启动引导类所在的包及其子包return this.packageName;}

@AutoConfigurationImportSelector

    public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return NO_IMPORTS;} else {// 获取自动化配置的元数据AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);// 通过配置的元数据和注解的元数据,得到一个自动化配置的entry键值对AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}}
    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} else {// 获取注解的属性AnnotationAttributes attributes = this.getAttributes(annotationMetadata);// 通过注解元数据和属性获取真正意义上的集合List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);configurations = this.removeDuplicates(configurations);Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);this.checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);configurations = this.filter(configurations, autoConfigurationMetadata);this.fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);}}
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;}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 {// 加载配置文件中的信息Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");LinkedMultiValueMap result = new LinkedMultiValueMap();while(urls.hasMoreElements()) {URL url = (URL)urls.nextElement();UrlResource resource = new UrlResource(url);// 遍历配置文件中的信息,转换为Properties对象,放入到信息中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;} catch (IOException var13) {throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);}}}

META-INF/spring.factories

    @Configuration// 是否自动配置的条件@ConditionalOnWebApplication(type = Type.SERVLET)// 判断是否有下面三个的配置的@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})@AutoConfigureOrder(-2147483638)@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})public class WebMvcAutoConfiguration {

SpringApplication.run(XXX.class, args)

    // public static ConfigurableApplicationContext run()返回一个Spring容器对象public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return (new SpringApplication(primarySources)).run(args);}

创建SpringApplication对象

    public SpringApplication(Class... primarySources) {this((ResourceLoader)null, primarySources);}
    public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {this.sources = new LinkedHashSet();this.bannerMode = Mode.CONSOLE;this.logStartupInfo = true;this.addCommandLineProperties = true;this.addConversionService = true;this.headless = true;this.registerShutdownHook = true;this.additionalProfiles = new HashSet();this.isCustomEnvironment = false;this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));// 判断当前是否是web环境this.webApplicationType = WebApplicationType.deduceFromClasspath();  // 从类路径下找到META‐INF/spring.factories配置的所有ApplicationContextInitializer;// 然后封装成一个Map,转成Set,遍历Set,通过反射创建对象,// 赋值给SpringApplication的initializers属性this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));// 从类路径下找到META‐INF/spring.factories配置的所有ApplicationListener;// 然后封装成一个Map,转成Set,遍历Set,通过反射创建对象,// 赋值给SpringApplication的listeners属性this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));// 从多个配置类中找到有main方法的主配置类this.mainApplicationClass = this.deduceMainApplicationClass();}

执行run方法

    public ConfigurableApplicationContext run(String... args) {// 创建StopWatch对象,执行start方法,开始计时。StopWatch用来计算run方法的执行时间StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();this.configureHeadlessProperty();// 从类路径下META‐INF/spring.factories中获取SpringApplicationRunListeners,// 反射创建对象,并回调start方法;SpringApplicationRunListeners listeners = this.getRunListeners(args);listeners.starting();Collection exceptionReporters;try {// 准备命令行参数,就是传入的argsApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 准备环境,完成后,回调listener的environmentPrepared方法。ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);this.configureIgnoreBeanInfo(environment);// 打印SpringBoot的logoBanner printedBanner = this.printBanner(environment);// 创建Spring容器,通过判断,决定是web的Spring容器还是普通的Spring容器context = this.createApplicationContext();exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);// 准备上下文环境this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);// 刷新容器,加载所有的组件【如果是web环境,会启动tomcat】this.refreshContext(context);this.afterRefresh(context, applicationArguments);// 停止计时,stopWatch.stop();if (this.logStartupInfo) {(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);}// 回调所有的SpringApplicationRunListener的started();listeners.started(context);// 从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调// 【ApplicationRunner先回调,CommandLineRunner再回调】this.callRunners(context, applicationArguments);} catch (Throwable var10) {this.handleRunFailure(context, var10, exceptionReporters, listeners);throw new IllegalStateException(var10);}try {listeners.running(context);return context;} catch (Throwable var9) {this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);throw new IllegalStateException(var9);}}

【Spring框架家族】SpringBoot自动配置原理源码跟进相关推荐

  1. SpringBoot自动配置【源码分析】-初始加载自动配置类

    @Import(AutoConfigurationImportSelector.class) 1.利用getAutoConfigurationEntry(annotationMetadata);给容器 ...

  2. 【Spring框架家族】SpringBoot自动配置基本实现

    SpringBoot自动配置-Condition_1 Condition是Spring4.0后引入的条件化配置接口,通过实现Condition接口可以完成有条件的加载相应的Bean @Conditio ...

  3. 深入解析SpringBoot核心运行原理和运作原理源码

    SpringBoot核心运行原理 Spring Boot 最核心的功能就是自动配置,第 1 章中我们已经提到,功能的实现都是基于"约定优于配置"的原则.那么 Spring Boot ...

  4. SpringBoot实战之SpringBoot自动配置原理

    www.cnblogs.com/leihuazhe/p- SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConf ...

  5. SpringBoot(2.4.0)自动配置原理(源码)

    一.从@SpringBootApplication讲起 源码 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Docu ...

  6. SpringBoot自动配置原理流程

    前言 新公司太忙了,都没啥空更新博客,就随便记录一下以前的学习笔记吧.SpringBoot是基于Spring上的衍生框架,只要看懂了Spring的话,学这个就比较简单了:SpringBoot也是在当前 ...

  7. springboot自动配置的原理_SpringBoot实战:详解SpringBoot自动配置原理

    SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...

  8. springboot自动配置_揭秘SpringBoot自动化配置

    花絮# 几年前接触过SpringBoot,跑过Demo,当时刚入行,连Spring都没搞明白,更别说SpringBoot了,就是觉得,哇塞,好厉害,然后一脸懵逼. 工作中没有用到,又没有去主动学习它. ...

  9. 【详解】面试必问:SpringBoot自动配置原理

    前言 SpringBoot框架是开发中的一大利器,其简化了spring的xml的配置,遵循了"约定大于配置"的原则,使用注解对常用的配置做默认配置,减少使用xml配置模式.Spri ...

最新文章

  1. Linux下基于密钥的安全验证实现方法
  2. 3.IT-解决方案-3-Backup-Sql
  3. 当SRS遇到K8s:如何构建海量推流源站?
  4. 使用TPU的注意事项
  5. 《深入理解分布式事务》第三章 Spring 事务的实现原理
  6. paip.jdbc 连接自动释放的测试
  7. 奋战聊天机器人(二)语料和词汇资源
  8. 基于Matlab使用激光雷达从点云到跟踪列表跟踪车辆仿真(附源码)
  9. (九)DFI接口时序
  10. 为什么设置了面容ID,仍然需要输入密码解锁iPhone?
  11. css如何将图片调成合适大小,如何利用CSS自动调整图片的大小
  12. 隐私公链背景的FAIRY SWAP,让DEX更进一步
  13. 为知笔记(PC端) 康奈尔模板各栏间距调整
  14. android 服务开机启动慢,Android App启动慢原因
  15. AI自己写代码让智能体进化!OpenAI的大模型有“人类思想”那味了
  16. 《寓言中的经济学》简明纪要 - Part 1
  17. 单元测试:通过读取csv/xml数据并且结合使用allure展示测试报告,验证开发中的add()和reduct()操作(在@allure.story分别实现相加减)
  18. Q1月活大涨70%,后浪会成B站的流量萌新吗?
  19. L1正则化与L2正则化
  20. JAVA的GUI编程02——事件监听(ActionListener)、TextField事件监听、(组合、内部类)

热门文章

  1. Linux中LVM(逻辑卷管理)的使用
  2. 为什么用lazy启动eclipse的时候,插件activator的start自动被调用
  3. Android异步下载网络图片(其二:AsyncTask)
  4. CSS的三种使用方式
  5. Android中程序向桌面和Launcher添加快捷方式
  6. grep+awk+sort+wc实战
  7. 嵌入式ARM启动代码的工作
  8. 嵌入式开发试题1-100
  9. 野指针和悬空指针的形成原因和如何避免!
  10. Linux各版本完整发展图