SpringBoot《第二课》
2022年9月5号 SpringBoot自动配置原理初步了解SpringBoot原理。
第一点解析Pom.xml文件信息下面是配置文件的具体信息。
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-test</artifactId><version>2.7.3</version><scope>test</scope></dependency>
</dependencies>
第一张图:带你了解Pom.xml文件:
让我们来看一下上面流程图的过程吧!这里涉及到源码
1 认真观察你会发现pom.xml文件中有两次的父依赖的关系
2 第一次父依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.3</version><relativePath/> <!-- lookup parent from repository --></parent>
3 第二次父依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.7.3</version></parent>
4 spring-boot-dependencies 这个包在Maven的学习中见过吧
<groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.7.3</version><packaging>pom</packaging><name>spring-boot-dependencies</name>
5 进一步的深入了解一下
<licenses><license><name>Apache License, Version 2.0</name><url>https://www.apache.org/licenses/LICENSE-2.0</url></license></licenses>
6 第一次小的总结:spring-boot-dependencies 帮我们管理了SpringBoot开发环境中应用中所有应用中所有的依赖版本,解决了第三方库的冲突问题。
因此:spring-boot-dependencies称为 SpringBoot版本仲裁中心。
7 启动器的概念: spring-boot-starter-xxx 简称为启动器
启动器:说白了又是SpringBoot的启动场景
比如 spring-boot-starter-web,他又会导入所有的web环境所有的依赖
8 springboot官网介绍的应用场景的地址 在下面
https://docs.spring.io/spring-boot/docs/current/reference/html/dependency-versions.html#appendix.dependency-versions
9 下面是一些Springboot应用场景在官网中找到的
spring-boot-starter-test
|
起动器测试弹簧启动应用程序和库包括JUnit木星,Hamcrest和5 |
spring-boot-starter-thymeleaf
|
起动器构建MVC web应用程序使用Thymeleaf视图 |
spring-boot-starter-validation
|
起动器与Hibernate验证框架的使用Java Bean验证 |
spring-boot-starter-web
|
为构建web起动器,包括RESTful,使用Spring MVC应用程序。 使用Tomcat作为默认嵌入式容器 |
spring-boot-starter-web-services
|
起动器使用Spring Web服务 |
spring-boot-starter-webflux
|
起动器构建WebFlux应用程序使用Spring框架的反应网络的支持 |
spring-boot-starter-websocket
|
起动器来构建使用Spring框架的WebSocket支持WebSocket应用程序 |
第二张图:关于SpringApplication和Run方法的介绍:请看流程图.
/*** @ SpringBootApplication 标注的是一个SpringBoot的应用*/
@SpringBootApplication //标记成SpringBoot启动类 启动类下面所有的包public class Application {public static void main(String[] args) {//将SpringBoot应用启动//SpringApplication 类//run方法SpringApplication.run(Application.class,args);}
}
package org.springframework.boot;public class SpringApplication {public static final String BANNER_LOCATION_PROPERTY_VALUE = "banner.txt";public static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";private static final Log logger = LogFactory.getLog(SpringApplication.class);static final SpringApplicationShutdownHook shutdownHook = new SpringApplicationShutdownHook();
上面是有关:SpringApplication类的介绍
package org.springframework.boot;public class SpringApplication {public static final String BANNER_LOCATION_PROPERTY_VALUE = "banner.txt";public static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";private static final Log logger = LogFactory.getLog(SpringApplication.class);static final SpringApplicationShutdownHook shutdownHook = new SpringApplicationShutdownHook();private Set<Class<?>> primarySources;private Set<String> sources;private Class<?> mainApplicationClass;private Mode bannerMode;private boolean logStartupInfo;
上面是关于源码Run方法的介绍:关键在下面 new SpringApplication
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return (new SpringApplication(primarySources)).run(args);}
第二部分的总结
SpringApplication类的作用
这个类主要做了以下四件事情
1.推断应用的类型是普通的项目还是Web项目
2.查找并加载所有可用初始化器,设 置到initializers属性中.
3 找出所有的应用程序监听器,设置到listeners属性中
4.推断并设置main方法的定义类,找到运行的主类
Run方法
1 判断项目类型
2 推断当前主类
3 设置监听器 获取上下文 全面接管SpringMvc配置
4 找到运行主类
第三部分 @SpringBootApplication 一个注解才是SpringBoot的自动配置原理的核心。
SpringBoot自动配置原理核心@SpringBoot程序:
第一模块的学习
package com.java.controller.com.java;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;// @SpringBootApplication SpringBoot启动类(入口)
//@Configuration Spring.xml 页是配置类
//ComponentScan =<context:ComponentScan ></context-ComponentScan > 扫描包名
//Spring底层在解析配置类:回去解析@ComponentScan,读取basePackage
//如果没有读取到,会将当前配置类所在的包当成扫描包 package com.java.controller.com.java;
//位置:最好放在需要扫描的包的根目录下面,或者说放在所有Bean的项目中/*** @ SpringBootApplication 标注的是一个SpringBoot的应用*/
@SpringBootApplication //标记成SpringBoot启动类 启动类下面所有的包public class Application {public static void main(String[] args) {//将SpringBoot应用启动//SpringApplication 类//run方法SpringApplication.run(Application.class,args);}
}
第一层 Application
package org.springframework.boot.autoconfigure;@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的配置
- @Configuration spring配置类
- @Component 说明这也是一个Spring组件
- @EnableAutoConfiguration 自动配置
- @AutoConfigurationPackage 自动配置包 导入了选择器
- @Import({AutoConfigurationImportSelector.class}) 自动配置 包的注册
第二模块:SpringBootConfiguration 让程序进入
package org.springframework.boot;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;
}
然后进入@Configuration
package org.springframework.context.annotation;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {@AliasFor(annotation = Component.class)String value() default "";boolean proxyBeanMethods() default true;
}
最后进入到@Component中去你会发现下面内容
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//package org.springframework.context.annotation;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {@AliasFor(annotation = Component.class)String value() default "";boolean proxyBeanMethods() default true;
}
第三模块:
@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}
)}
进入@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程序中去
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//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.boot.autoconfigure.AutoConfigurationPackages.Registrar;
import org.springframework.context.annotation.Import;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {String[] basePackages() default {};Class<?>[] basePackageClasses() default {};
}
然后返回到下面的页面
package org.springframework.boot.autoconfigure;@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 {};
}
在上面的代码中找到:
AutoConfigurationImportSelector.class 点进去
第四模块:
package org.springframework.boot.autoconfigure;public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {private static final AutoConfigurationImportSelector.AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationImportSelector.AutoConfigurationEntry();private static final String[] NO_IMPORTS = new String[0];private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";private ConfigurableListableBeanFactory beanFactory;private Environment environment;private ClassLoader beanClassLoader;private ResourceLoader resourceLoader;private AutoConfigurationImportSelector.ConfigurationClassFilter configurationClassFilter;public AutoConfigurationImportSelector() {}
在上面的源码的基础上往下翻
在上面的图片中找到
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
获取所有的配置
然后点击getCandidateConfigurations这个单词
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(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.getConfigurationClassFilter().filter(configurations);this.fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);}}
然后你会发现
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");return configurations;}
第五模块:下面的单词有三个重点
SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass()
先看第一个getSpringFactoriesLoaderFactoryClass() 单点击是 return EnableAutoConfiguration.class 程序的出口找到
protected Class<?> getSpringFactoriesLoaderFactoryClass() {return EnableAutoConfiguration.class;}
在点击第二个单词:loadFactoryNames 获取所有的配置名 点进去看一下
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {ClassLoader classLoaderToUse = classLoader;if (classLoader == null) {classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();}String factoryTypeName = factoryType.getName();return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());}
SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass()
最后一个单词SpringFactoriesLoade 点击进去
第六模块
public final class SpringFactoriesLoader {public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);static final Map<ClassLoader, Map<String, List<String>>> cache = new ConcurrentReferenceHashMap();private SpringFactoriesLoader() {}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");return configurations;}
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {Map<String, List<String>> result = (Map)cache.get(classLoader);if (result != null) {return result;} else {HashMap result = new HashMap();try {Enumeration urls = classLoader.getResources("META-INF/spring.factories");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 factoryTypeName = ((String)entry.getKey()).trim();String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());String[] var10 = factoryImplementationNames;int var11 = factoryImplementationNames.length;for(int var12 = 0; var12 < var11; ++var12) {String factoryImplementationName = var10[var12];((List)result.computeIfAbsent(factoryTypeName, (key) -> {return new ArrayList();})).add(factoryImplementationName.trim());}}}
结论: springboot所有 自动配置都是在启动的时候扫描并加载: spring . factories所有的自动配置类都在这里面,但是不一-定生效, 要判断条件是否成立,只要导入了对应的start,就有对应的启动器了,有了启动器,我们自动装配就会生效,然后就配置成功!
springboot在启动的时候,从类路径下/META-INF/ spring . factories获取指定的值;
将这些自动配置的类导入容器,自动配置就会生效,帮我进行自动配置!
以前我们需要自动配置的东西,现在springboot帮我们做了
整合javaEE,解决方案和自动配置的东西都在spring-boot-autoconfigure-2.2.0.RELEASE.jar这个包下
它会把所有需要导入的组件,以类名的方式返回,这些
组件就会被添加到容器;
容器中也会存在非常多的xxAutoConfiguration的文件(@Bean),就是这些类给容器中导入了这个场景需要的所有组件;并自动配置,@Configuration ,JavaConfig!
有了自动配置类,免去了我们手动编写配置文件的工作!
核心要义 继承继承在继承 封装封装在封装
实现了SpringBoot自动配置
SpringBoot《第二课》相关推荐
- 继承WebMvcConfigurer 和 WebMvcConfigurerAdapter类依然CORS报错? springboot 两种方式稳定解决跨域问题
继承WebMvcConfigurer 和 WebMvcConfigurerAdapter类依然CORS报错???springboot 两种方式稳定解决跨域问题! 之前我写了一篇文章,来解决CORS报错 ...
- Dockerfile springboot项目拿走即用,将yml配置文件从外部挂入容器
Dockerfile 将springboot项目jar包打成镜像,并将yml配置文件外挂. # 以一个镜像为基础,在其上进行定制.就像我们之前运行了一个 nginx 镜像的容器,再进行修改一样,基础镜 ...
- SpringBoot部署脚本,拿走即用!
一个可以直接拿来使用的shell脚本,适用于springboot项目 #!/bin/bash # 这里可替换为你自己的执行程序,其他代码无需更改,绝对路径相对路径均可. # 若使用jenkins等工具 ...
- SpringBoot项目使用nacos,kotlin使用nacos,java项目使用nacos,gradle项目使用nacos,maven项目使用nacos
SpringBoot项目使用nacos kotlin demo见Gitte 一.引入依赖 提示:这里推荐使用2.2.3版本,springboot与nacos的依赖需要版本相同,否则会报错. maven ...
- springboot整合swagger2之最佳实践
来源:https://blog.lqdev.cn/2018/07/21/springboot/chapter-ten/ Swagger是一款RESTful接口的文档在线自动生成.功能测试功能框架. 一 ...
- SpringBoot中实现quartz定时任务
Quartz整合到SpringBoot(持久化到数据库) 背景 最近完成了一个小的后台管理系统的权限部分,想着要扩充点东西,并且刚好就完成了一个自动疫情填报系统,但是使用的定时任务是静态的,非常不利于 ...
- Springboot 利用AOP编程实现切面日志
前言 踏入Springboot这个坑,你就别想再跳出来.这个自动配置确实是非常地舒服,帮助我们减少了很多的工作.使得编写业务代码的时间占比相对更大.那么这里就讲一下面向切面的日志收集.笔者使用lomb ...
- 【Springboot】日志
springBoot日志 1.目前市面上的日志框架: 日志门面 (日志的抽象层): JCL(Jakarta Commons Logging) ...
- 【springboot】配置
配置文件 SpringBoot使用一个全局的配置文件,配置文件名是固定的: •application.properties •application.yml 配置文件的作用:修改SpringBoot自 ...
- 【springboot】入门
简介: springBoot是spring团队为了整合spring全家桶中的系列框架做研究出来的一个轻量级框架.随着spring4.0推出而推出,springBoot可以説是J2SEE的一站式解决方案 ...
最新文章
- mysql binlog的查询
- CUDA:利用Pytorch查看自己电脑上CUDA版本及其相关信息
- vue init失败解决方案-终极版
- 如何使用代码确定设备屏幕大小类别(小,普通,大,xlarge)?
- 【路径规划】基于matlab蚁群和粒子群算法双机器人协调路径规划【含Matlab源码 045期】
- 种一棵树最好的时间是十年前,其次是现在。
- git输入 ssh-keygen -t rsa 后只显示Generating public/private rsa key pair. 然后就直接跳出了
- 服务器安装linux系统教程
- 千呼万唤始出来—2019 FLAG
- Python如何使用Any和All?代码示例和解析
- python从云端服务器读数据_云服务器简单实现Python自动运维
- 菜鸟Django--更改和删除
- 羡慕华为人年薪110万?先看看华为员工的16项标准!
- Android studio 编译错误:CreateProcess error=206, 文件名或扩展名太长。
- FPGA数字信号处理(四)Quartus FIR IP核实现
- Carrot保卫萝卜
- 2023年广东数据分析师CPDA认证招生简章(理论+实战)
- easyui datebox时间控件改为年月视图,值也为年月
- SQL Server的彻底卸载与再次安装
- 八类患病番茄叶片图像数据集