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方法

SpringBoot-运行原理(四)的更多相关文章

  1. SpringBoot运行原理

    如果我们使用的是SpringApplication的静态run方法,那么,这个方法里面首先要创建一个SpringApplication对象实例,然后调用这个创建好的SpringApplication的 ...

  2. springboot深入学习(二)-----profile配置、运行原理、web开发

    一.profile配置 通常企业级应用都会区分开发环境.测试环境以及生产环境等等.spring提供了全局profile配置的方式,使得在不同环境下使用不同的applicaiton.properties ...

  3. Spring boot运行原理-自定义自动配置类

    在前面SpringBoot的文章中介绍了SpringBoot的基本配置,今天我们将给大家讲一讲SpringBoot的运行原理,然后根据原理我们自定义一个starter pom. 本章对于后续继续学习S ...

  4. SpringBoot:运行原理探究

    西部开源-秦疆老师:基于SpringBoot 2.1.6 的博客教程 秦老师交流Q群号: 664386224 未授权禁止转载!编辑不易 , 转发请注明出处!防君子不防小人,共勉! SpringBoot ...

  5. springboot 的运行原理?

    一.@SpringbootApplicaion 是一个组合注解?  在注解中点击查看. 作用:实现自动配置. /* * springboot的运行原理 1. @SpringbootApplicatio ...

  6. Js基础知识(四) - js运行原理与机制

    js运行机制 本章了解一下js的运行原理,了解了js的运行原理才能写出更优美的代码,提高运行效率,还能解决开发中遇到的不理解的问题. 进程与线程 进程是cpu资源分配的最小单位,进程可以包含多个线程. ...

  7. SpringBoot启动原理及相关流程

    一.springboot启动原理及相关流程概览 springboot是基于spring的新型的轻量级框架,最厉害的地方当属自动配置.那我们就可以根据启动流程和相关原理来看看,如何实现传奇的自动配置 二 ...

  8. SpringBoot-02 运行原理初探

    SpringBoot-02 运行原理初探 本篇文章根据b站狂神编写 pom.xml 2.1.父依赖 其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件! <parent> < ...

  9. 狂神说SpringBoot02:运行原理初探

    狂神说SpringBoot系列连载课程,通俗易懂,基于SpringBoot2.2.5版本,欢迎各位狂粉转发关注学习. 微信公众号:狂神说(首发)    Bilibili:狂神说Java(视频) 未经作 ...

  10. ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行

    ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行 核心框架 ASP.NET Core APP 创建与运行 总结 之前两篇文章简析.NET Core 以及与 .NET Framew ...

随机推荐

  1. 由浅入深——从ArrayList浅谈并发容器

    原创作品转载请附:https://www.cnblogs.com/superlsj/p/11655523.html 一.一个案例引发的思考 public class ArrayListTest { p ...

  2. RouterOS安装以及搭建DHCP PPPoE PPTP L2TP服务

    1.安装routeros https://mikrotik.com/download 网站下载routeros镜像 vdi格式 :VirtualBox默认创建的硬盘文件格式 vmdk格式:VMware ...

  3. Android Debug 之 Log 最佳实践

    本文微信公众号「AndroidTraveler」首发. 背景 在开发过程中,调试是必不可少的一项工作. 当我们要确定项目的逻辑时,当我们要了解界面的生命周期时,当我们发现新写的逻辑与期望效果不一致时, ...

  4. 云服务器linux系统修改时间和时区

    申请的云服务器时间不对,用同步网络时间的命令执行后依然有问题. 解决办法: # tzselect [root@ylyuat2-web02 logs]# TZ='Asia/Shanghai'[root@ ...

  5. CGI、FastCGI、CLI、Apache、ISAPI之PHP运行环境对比

    1.运行模式 关于PHP目前比较常见的五大运行模式: 1)CGI(通用网关接口 / Common Gateway Interface) 2)FastCGI(常驻型CGI / Long-Live CGI ...

  6. Docker解决下载镜像速度慢

    Docker安装好以后要用Docker pull命令下载镜像,但是会出现下载很慢的现象.Docker默认是国外的源,配置国内镜像仓库. 1.cd /etc/docker/路径下 2.编辑daemon. ...

  7. 高质量App的架构设计与思考!

    最近在做一功能不大.业务也不复杂的小众App,以往做App是发现自己从来没有考虑过一些架构方面的问题,只是按照自己以往的习惯去写代码,忽略了App的设计.本次分享主要包含一些开发App的小经验和技巧, ...

  8. FB力挺的Pytorch深度学习 书本来了

    获得 fb首席科学家力挺的 pytorch教程 发布啦, 看截图 ![file](https://img2018.cnblogs.com/blog/1876748/201911/1876748-201 ...

  9. Redis的内存淘汰策略

    Redis占用内存大小 我们知道Redis是基于内存的key-value数据库,因为系统的内存大小有限,所以我们在使用Redis的时候可以配置Redis能使用的最大的内存大小. 1.通过配置文件配置 ...

  10. Python开发面试集锦

    我正在编写一套python面试开发集锦,可以帮忙star一下,谢谢! 地址:GitHub专栏