SpringBoot 原理
约定优于配置
> 实际应用中,我们90%以上的框架的项目配置都是差不多的,所以Spring团队,就弄出来了一个我们大家通用的配置,以后我们开发项目时就不需要再去配置这些繁琐的配置了
就比如:
当我们使用SSM框架,所有的maven依赖和版本都需要我们程序员自己去控制,去找寻相对应的依赖,并且如果依赖没有配合好,jar包冲突,还需要我们自己去解决,并且这个解决是非常耗时的
而springboot中 我们在创建Springboot项目后,即会在文件
spring-boot-starter-parent->spring-boot-dependencies中看到所有SpringBoot为我们创建好的约定配置
即:SpringBoot已经为我们配置好了大部分应用的版本配置等
那么,我们应该怎么去使用他呢?
全局配置的名称必须为application
开箱即用
SpringBoot 中的每一个Starter都是一个功能场景
<!--WEB场景启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
比如我们在项目pom.xml中配置的依赖 spring-boot-starter-web
他的作用就是为我们启动spring中配置好的Web场景
Starter就是一个启动器
spring boot的依赖关系
我们新建一个项目:将项目的所有依赖全部删除,会发现我们在SpringBoot项目中的启动类不能使用了,我们需要给他添加下列一个核心依赖:
无法使用
为他添加一个核心依赖
<!--SpringBoot的核心依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
添加此核心依赖后的核心jar包
添加此核心代码之后springboot启动类就能够启动了,但是因为没有添加spring的web依赖,他在启动之后就直接结束了。并不能通过他访问我们的8080接口
现在我们添加web启动器依赖
<!--web应用场景启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
在进行执行
他的服务器就启动成功了
因为springboot内置了tomcat,我们使用启动器后即可以直接使用他进行web访问
maven的标准的目录结构
目录结构介绍以及springboot配置文件
资源文件中多存放SpringBoot的配置文件 如:
application.properties的配置
或者是 application.yml的配置
在static和templates中可以存放我们需要的网页资源
这三种配置文件都能够配置springboot
三种文件配置优先级:
properties>yml>yaml
通常官方推荐使用yml
探索底层
注解
@SpringBootApplication
在启动类中找到@SpringBootApplication注解 并且ctrl+鼠标点击 进入注解中
发现除了注解的声明之外还有四个不同的注解
@SpringBootConfiguration
@Configuration
@Component
他的作用相当于我们在spring中的bean文件 自动创建我们需要的bean 并且交给springboot去维护管理
@EnableAutoConfiguration:这个注解 他所加载的组件,就是我们在pom中所声明的组件 以及SpringBoot默认给我们提供的组件 将组件实例化,交由我们的ioc容器去管理
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
@ComponentScan:扫描器 扫描我们写的一些组件,扫描的是启动类包下的所有组件
扫描的组件注解种类:@Server @Repository @Component
@Filter
**@EnableAutoConfiguration:**是我们的核心注解,开启自动配置/装配
@EnableAutoConfiguration:这个注解 他所加载的组件,就是我们在pom中所声明的组件 以及SpringBoot默认给我们提供的组件 将组件实例化,交由我们的ioc容器去管理
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
核心中的核心
AutoConfigurationImportSelector.class类:
查看这个方法内的获取自动导入的方法
进入这个方法里面 打入一个断点,我们对他进行一下调试
筛选完成后,即只需要用到我们的23个包了
此时我们关闭调试,在pom中添加一个starter启动依赖
我们导入一个thymeleaf启动依赖
添加之后我们再次进行调试
到达过滤器,进行下一步
这时发现他已经变成了24个了
启动类>@SpringBootApplication>@EnableAutoConfiguration>@Import({AutoConfigurationImportSelector.class})>
public String[] selectImports(AnnotationMetadata annotationMetadata) > this.getAutoConfigurationEntry(annotationMetadata)>getCandidateConfigurations(annotationMetadata, attributes)>SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader())>return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList())
进入到一个加载Spring文件的工厂类
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
他通过此行代码查找jar包中的资源位置 并对他们进行自动加载
我们去找到此行代码所说明的文件位置
找到spring-boot-autoconfiure–>在此包下找到他的地址META-INF/spring.factories
点击进入文件 发现他的配置文件中的
148-21 = 127 行
由此可以发现springboot的候选配置文件就是在这个文件中获取的
获取到了这127个文件后进入过滤器,根据pom导入的包和springboot自带包进行过滤后获取的就是我们启动此次服务器所需要的包了
他会在找到需要的包后
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
通过这两个注解自动导入我们的包
程序
SpringApplication
源码剖析
/**
* Create a new {@link SpringApplication} instance. The application context will load
* beans from the specified primary sources (see {@link SpringApplication class-level}
* documentation for details. The instance can be customized before calling
* {@link #run(String...)}.
* @param resourceLoader the resource loader to use
* @param primarySources the primary bean sources
* @see #run(Class, String[])
* @see #setSources(Set)
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 初始化资源加载器
this.resourceLoader = resourceLoader;
// 资源加载类不能为 null
Assert.notNull(primarySources, "PrimarySources must not be null");
// 初始化加载资源类集合并去重
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推断应用程序是不是web应用
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 设置初始化器(Initializer)
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断出主应用入口类
this.mainApplicationClass = deduceMainApplicationClass();
}
123456789101112131415161718192021222324252627
其中,在推断应用程序是不是web应用的时候调用了deduceFromClasspath() 方法
run方法
配置的归根结底都是通过类属性进行配置的
properties 所有的配置的底层都对应了一个类的属性