1. SpringBoot 的特性

https://www.bilibili.com/video/BV1Et411Y7tQ?p=117&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204

1.1. 依赖管理

1.1.1. 父项目做依赖管理

1、无需关注版本号,自动版本仲裁
2、可以修改默认版本号

1.1.2. starter 场景启动器

image.png

1、见到很多 spring-boot-starter-xxx : xxx 就某种场景
2、只要引入 starter,这个场景的所有常规需要的依赖我们都自动引入
3、SpringBoot 所有支持的场景
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
4、见到的 xxx-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
5、所有场景启动器最底层的依赖

1.2. 自动配置

● 自动配好 Tomcat
○ 引入 Tomcat 依赖。
○ 配置 Tomcat
● 自动配好 SpringMVC
○ 引入 SpringMVC 全套组件
○ 自动配好 SpringMVC 常用组件(功能)
● 自动配好 Web 常见功能,如:字符编码问题
○ SpringBoot 帮我们配置好了所有 web 开发的常见场景
● 默认的包结构
○ 主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
○ 无需以前的包扫描配置
○ 想要改变扫描路径,@SpringBootApplication(scanBasePackages=”com.atguigu”)
● 或者@ComponentScan 指定扫描路径
● 各种配置拥有默认值
○ 默认配置最终都是映射到某个类上,如:MultipartProperties
○ 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
● 按需加载所有自动配置项
○ 非常多的 starter
○ 引入了哪些场景这个场景的自动配置才会开启
○ SpringBoot 所有的自动配置功能都在 spring-boot-autoconfigure 包里面

2. 谈谈你对 SpringBoot 的理解 (优点特性)

SpringBoot 的用来快速开发 Spring 应用的一个脚手架、其设计目的是用来简新 Spring 应用的初始搭建以及开发过程。

  1. SpringBoot 提供了很多内置的 Starter 结合自动配置,实现了对主流框架的无配置集成、开箱即用;
  2. SpringBoot 简化了开发,采用 JavaConfig 的方式可以使用零 xml的方式进行开发;
  3. SpringBoot内置 Web 容器无需依赖外部 Web 服务器,省略了 Web.xml,直接运行 jar 文件就可以启动 web 应用;
  4. SpringBoot 帮我管理了常用的第三方依赖的版本,减少出现版本冲突的问题;
  5. SpringBoot自带了监控功能,可以监控应用程序的运行状况,或者内存、线程池、Http 请求统计等,同时还提供了优雅关闭应用程序等功能。

3. SpringBoot 自动配置原理 -@SpringBootApplication ⭐️🔴

%%
▶1.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230303-0844%%

^py2rrk
https://www.yuque.com/atguigu/springboot/qb7hy2#UJZFM ^c46210

3.1. 引导加载自动配置类

%%
▶1.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230326-2214%%
❕ ^dxovlh

1
2
3
4
5
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication{}

3.1.1. @SpringBootConfiguration

@Configuration。代表当前是一个配置类

3.1.2. @ComponentScan

指定扫描哪些,是一个 Spring 注解;
在 SpringBoot 中,在该注解属性中配置了排除规则:排除 2 种类型:
①继承了 TypeExcludeFilter 的类
②SpringBoot 的自动配置类

1
2
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),  
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

3.1.3. @EnableAutoConfiguration

image.png

3.1.3.1. @AutoConfigurationPackage

%%
▶6.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230324-1703%%
❕ ^j6d450

@Import(AutoConfigurationPackages.Registrar.class)
自动配置包,指定了默认的包规则,将指定的一个包下的所有组件导入进来。

1
2
3
4
5
@Import(AutoConfigurationPackages.Registrar.class)  
//给容器中导入一个组件
public @interface AutoConfigurationPackage {}
//利用Registrar给容器中导入一系列组件
//将指定的一个包下的所有组件导入进来,MainApplication 所在包下。

image.png

image.png

3.1.3.2. @Import(AutoConfigurationImportSelector.class)

image.png

selectImports→getAutoConfigurationEntry 获取到所有需要导入到容器中的配置类

方法调用路径
AutoConfigurationImportSelector. getAutoConfigurationEntry ==→== SpringFactoriesLoader. loadSpringFactories ==→==
classLoader.getResources(“META-INF/spring.factories“)

默认扫描当前系统里面所有 META-INF/spring.factories 位置的文件%%
▶2.🏡⭐️◼️自定义 starter 就是依靠这种策略 ?🔜MSTM📝 可以被扫描到需要注入的组件◼️⭐️-point-20230226-0847%%

比如 spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories

1
2
3
4
5
6
7
1、利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
2、调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
3、利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件
4、从META-INF/spring.factories位置来加载一个文件。
默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories

image.png

3.1.3.2.1. SPI 原理

%%
▶2.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230305-0804%%
❕ ^bypdob

image.png

image.png

3.2. 按需开启自动配置项

虽然我们 127 个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration,但按照条件装配规则(@Conditional),最终会按需配置。

3.3. 修改默认配置

1
2
3
4
5
6
7
8
9
10
11
@Bean
@ConditionalOnBean(MultipartResolver.class) //容器中有这个类型组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {
//给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
//SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
// Detect if the user has created a MultipartResolver but named it incorrectly
return resolver;
}
给容器中加入了文件上传解析器;

SpringBoot 默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先

3.4. 与 SpringMVC 配置的区别

3.4.1. 关于 JSON 编码配置

Spring 整合 SpringMVC 时需要设置 JSON 格式
Springboot 不需要,因为在spring-boot-starter-web
自动配置了 jacjson-databind,使用的是 MappingJackson2HttpMessageConverter

3.4.2. @EnableAspectJAutoProxy⭐️🔴

image.png

在 Spring 中,如果不在配置类中添加@EnableAspectJAutoProxy,那么所有 切面 注解是不生效的(springboot 因为有自动配置,所以不需要开发人员手工配置@EnableAspectJAutoProxy)

3.5. 自动配置总结

  • SpringBoot 先加载所有的自动配置类 xxxxxAutoConfiguration
  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties 里面拿。xxxProperties 和配置文件进行了绑定
  • 生效的配置类就会给容器中装配很多组件
  • 只要容器中有这些组件,相当于这些功能就有了
  • 定制化配置
    • 用户直接自己@Bean 替换底层的组件
    • 用户去看这个组件是获取的配置文件什么值就去修改。

xxxxxAutoConfiguration —> 组件 —> xxxxProperties 里面拿值 —-> application.properties

3.6. 黑马补充

https://www.bilibili.com/video/BV15b4y117RJ?p=172&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204
image.png

4. SpringBoot 的启动原理⭐️🔴

%%
▶15.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230305-1327%%
❕ ^ro0jas
%%
▶1.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230324-0703%%
❕ ^214fh8

概述

  1. 运行 main 方法: 初始化 new SpringApplication  从 spring.factories  读取 ApplicationListener、ApplicationContextInitializer
  2. 运行 run 方法
  3. 读取环境变量配置信息
  4. 创建 springApplication 上下文: ServletWebServerApplicationContext
  5. 预初始化上下文 
  6. 调用 refresh 加载 ioc 容器 
    invokeBeanFactoryPostProcessor   解析@Import:  加载所有的自动配置类
    onRefresh  创建 (内置)servlet 容器
    image.png

在这个过程中 springboot 会调用很多监听器对外进行扩展
https://www.bilibili.com/video/BV1Et411Y7tQ?p=196&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204

4.1. 创建 SpringApplication

image.png

  1. 判定当前应用的类型。ClassUtils.isPresent → WebApplicationType.SERVLET
  2. 使用系统方法 getSpringFactoriesInstances 分别查找以下类型:
    ○ 查找 bootstrappers:==初始启动引导器==
    spring.factories 文件中找 org.springframework.boot. Bootstrapper
    放入 List<Bootstrapper>
    ○ 查找 ApplicationContextInitializer:==初始化器==
    去 spring.factories 找 ApplicationContextInitializer
    放入 List<ApplicationContextInitializer<?>> initializers
    ○ 查找 ApplicationListener :==应用监听器==
    去 spring.factories 找 ApplicationListener
    放入 List<ApplicationListener<?>> listeners
  3. 保存当前启动类为配置类

4.2. 运行 SpringApplication

4.2.1. 记录应用的启动时间 - 创建引导上下文 -bootstrappers.intitialize

StopWatch,记录应用的启动时间
○ 创建引导上下文(Context 环境)createBootstrapContext()
获取到所有之前的 bootstrappers 挨个执行 intitialize() 来完成对引导启动器上下文环境设置
○ 让当前应用进入 headless 模式。java.awt.headless

4.2.2. 发布 ApplicationStartingEvent 事件

获取所有 RunListener(运行监听器)【为了方便所有 Listener 进行事件感知】
■ getSpringFactoriesInstances 去 spring.factories 找 SpringApplicationRunListener.
遍历 SpringApplicationRunListener 调用 starting 方法
■ 相当于通知所有感兴趣系统正在启动过程的人,项目正在 starting。

4.2.3. 读取环境配置信息发布 environmentPreparedEvent

image.png

保存命令行参数;ApplicationArguments
○ 准备环境 prepareEnvironment();
■ 返回或者创建基础环境信息对象。StandardServletEnvironment
■ 配置环境信息对象。
● 读取所有的配置源的配置属性值:
ConfigFileApplicationListener 会监听 onApplicationEnvironmentPreparedEvent 事件来加载配置文件 application.properties 的环境变量

■ 绑定环境信息
■ 监听器调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成

image.png

image.png

4.2.4. 根据项目类型创建 IOC 容器⭐️🔴

实例化 Spring 上下文(createApplicationContext())
■ 根据项目类型(Servlet)创建相应的 WEB 容器
■ 当前会创建 AnnotationConfigServletWebServerApplicationContext

4.2.5. 准备 IOC 容器基本信息 (刷新前准备 -contextPrepared-loaded)

image.png

○ 准备 ApplicationContext IOC 容器的基本信息 prepareContext()
■ 保存环境信息
■ IOC 容器的后置处理流程。
■ 应用初始化器;applyInitializers;
遍历所有的 ApplicationContextInitializer 。调用 initialize。来对 ioc 容器进行初始化扩展功能
遍历所有的 listener 调用 contextPrepared。EventPublishRunListenr;通知所有的监听器 contextPrepared
● 将启动类作为配置类进行读取 –>将配置注册为 BeanDefinition 未看到有这块代码
■ 所有的监听器调用 contextLoaded通知所有的监听器 contextLoaded

image.png

4.2.6. 刷新 IOC 容器⭐️🔴

刷新 IOC 容器。refreshContext
■ 创建容器中的所有组件(Spring 注解)
○ 容器刷新完成后工作 afterRefresh 无实现,可扩展

AnnotationConfigServletWebServerApplicationContext.refresh

image.png
image.png

4.2.6.1. invokeBeanFactoryPostProcessors

invokeBeanFactoryPostProcessor   解析@Import:  加载所有的自动配置类
%%
▶1.🏡⭐️◼️SpringBoot 启动时配置类解析的时机 ?🔜MSTM📝 跟 Spring 是相同的,都是在第 5 步 invokeBeanFactoryPostProcessors。而且在 onrefresh 方法中创建了 Servlet 容器◼️⭐️-point-20230224-1821%%

4.2.6.2. onrefresh 创建子容器

image.png
onRefresh  创建 (内置)servlet 容器

4.2.7. 记录启动结束时间并输出

4.2.8. 发布 ApplicationStartedEvent

○ 所有监听器调用 listeners.started(context); 通知所有的监听器 started

4.2.9. 调用所有 runners

○ 调用所有 runners;callRunners()
■ 获取容器中的 ApplicationRunner
■ 获取容器中的 CommandLineRunner
■ 合并所有 runner 并且按照@Order 进行排序
■ 遍历所有的 runner。调用 run 方法
○ 如果以上有异常,
■ 调用 Listener 的 failed

4.2.10. 如果启动异常则发送 ApplicationFailedEvent

○ 调用所有监听器的 running 方法 listeners.running(context); 通知所有的监听器 running
○ running 如果有问题。继续通知 failed 。调用所有 Listener 的 failed;通知所有的监听器 failed

img

img

5. 嵌入式 Servlet 容器启动原理 V2

%%
▶4.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230324-0706%%
❕ ^kb445n

SpringBoot_V1: https://www.bilibili.com/video/BV1mf4y1c7cV/?p=79&spm_id_from=pageDriver&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204

SpringBoot_V2: https://www.bilibili.com/video/BV1Et411Y7tQ?p=169&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204

image.png

5.1. 引入依赖触发自动配置

5.1.1. 容器工厂自动配置类⭐️🔴

当引入 spring-boot-starter-web 依赖时会在 SpringBoot 中添加并生效
servlet 容器工厂自动配置类: ServletWebServerFactoryAutoConfiguration
(生效原理: @ConditionalOnWebApplication(type = Type.SERVLET))
V1: EmbeddedServletContainerAutoConfiguration

image.png

5.1.2. Web 容器工厂 - 默认 Tomcat

该自动配置类通过@Import 导入了 (通过@ConditionalOnClass 判断决定使用哪一个) 一个 Web 容器工厂(默认 web-starter 会导入 tomcat 包),即 TomcatServletWebServerFactory

image.png

5.1.3. Web 容器工厂定制化器的后置处理器

5.1.3.1. BeanPostProcessorsRegistrar

ServletWebServerFactoryAutoConfiguration 中还通过 BeanPostProcessorsRegistrar 引入了容器工厂定制化器的后置处理器 WebServerFactoryCustomizerBeanPostProcessor

image.png

WebServerFactoryCustomizerBeanPostProcessor,会获取所有的定制器,调用每个定制器的 customer 方法,用来给 Servlet 容器进行赋值

image.png

V1: EmbeddedServletContainerCustomizerBeanPostProcessor

5.1.3.2. WebServerFactoryCustomizer(容器工厂定制化器)⭐️🔴

我们在自定义容器配置时,也可以使用这个 WebServerFactoryCustomizer
示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;

@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

@Override
public void customize(ConfigurableServletWebServerFactory server) {
server.setPort(9000);
}

}

5.2. SpringBoot 应用执行 Run 方法

SpringApplication.run(Boot05WebAdminApplication.class, args);

5.2.1. 创建 IOC 容器

【创建 IOC 容器对象,并初始化容器,创建容器的每一个组件】;如果是 web 环境则创建 AnnotationConfig==ServletWebServer==ApplicationContext。如果不是 web 环境则创建 AnnotationConfigApplicationContext

image.png

SpringBoot_V2:
image.png

SpringBoot_V1:
image.png

5.2.2. 调用父类 refresh()

刷新创建好的 IOC 容器
image.png

5.2.3. 执行重写的 onRefresh() 方法

刷新 12 步中的第 9 步:web 的 IOC 容器 ServletWebServerApplicationContext 重写了 onRefresh 方法

image.png
%%
▶1.🏡⭐️◼️新技能 get ?🔜MSTM📝 前面的图标都点点看看◼️⭐️-point-20230227-0907%%

image.png

5.2.4. 从容器中获取 TomcatServletWebServerFactory

V1:EmbeddedServletContainerFactory
因为前面有@Bean 注解注入,所以可以从 IOC 容器中获取嵌入式的 Servlet 容器工厂 TomcatServletWebServerFactory,然后就可以用来创建 Servlet 容器
image.png

image.png

image.png

5.2.5. 后置处理器执行配置定制

image.png

当 TomcatServletWebServerFactory 创建 Servlet 容器对象时,后置处理器看这个对象,就来获取所有的定制器来定制 Servlet 容器的相关配置;

5.2.6. 创建 Servlet 容器并启动

通过 getWebServer 创建嵌入式的 Servlet 容器;
image.png

5.2.7. 顺序总结

IOC 容器启动时创建 Servlet 容器,然后先启动嵌入式的 Servlet 容器,最后再将 IOC 容器中剩下的没有创建出的对象创建出来

5.3. 概述

image.png
image.png
%%
▶2.🏡⭐️◼️SpringBoot 中 SpringMVC 与 Spring 整合的 SpringMVC 区别 ?🔜MSTM📝 一般的 SpringMVC 是需要启动子容器的,而 SpringBoot 中只有 1 个容器,SpringMVC 是通过注入自动配置类生成的◼️⭐️-point-20230224-1911%%

image.png

6. SpringBoot 外置 Tomcat 启动原理⭐️🔴

%%
▶3.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230324-0704%%
❕ ^er3z4j

https://www.bilibili.com/video/BV1Et411Y7tQ?p=51&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204

6.1. 操作步骤⭐️🔴

1、必须创建一个 war 项目;
2、将嵌入式的 Tomcat 指定为 provided

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>

3、必须编写一个 SpringBootServletInitializer 的子类,并重写 configure 方法里面的写法,遵照固定写法,将 SpringBoot 的启动类放入 application.sources 的方法参数中。 ❕%%
▶13.🏡⭐️◼️使用外置的 Tomcat 启动 SpringBoot 项目的方法 ?🔜MSTM📝 需要编写一个 SpringBootServletInitializer 的子类,并将 SpringBoot 启动类放入到重写的 Configurer 方法中 application.sources 的入参中。◼️⭐️-point-20230302-1656%%

1
2
3
4
5
6
7
8
9
public class ExternalServletInitializer extends SpringBootServletInitializer {

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
//传入SpringBoot的主程序,
return application.sources(SpringBoot04WebJspApplication.class);
}

}

4、启动服务器就可以;

6.2. 底层原理⭐️🔴

利用了 servlet3.0 规范官方文档:  当 servlet 容器启动时候就会去所有 jar 包中的 META-INF/services  文件夹中找到 javax.servlet.ServletContainerInitializer,有的 jar 包中存在这个文件并在里面会绑定一个 ServletContainerInitializer.   当 servlet 容器启动时候就会去该文件中找到 ServletContainerInitializer 的实现类,从而 创建它的实例并调用其 onstartUp 方法
%%
▶14.🏡⭐️◼️标准的 SPI 机制:Tomcat 启动后会遍历查看所有 jar 包中 META-INF/services 目录下的 javax.servlet.ServletContainerInitializer 文件中配置的全限定名为 org.springframework.web.SpringServletContainerInitializer,new Instance 并放入感兴趣的类集合中,遍历调用他们的 onstartup 方法;伪 SPI 机制:SpringBoot 的自动配置类的加载方式,启动时查找 META-INF/spring.factories 文件中 enableAutoConfiguration=xxx,\,根据每个类上@ConditionalOn 等条件判断,将 xxx 加载并创建 Bean◼️⭐️-point-20230302-1827%%

6.3. 执行流程

%%
▶9.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230305-1054%%
❕ ^7d9w7
1、启动 Tomcat 服务器
2、spring web 模块里有这个文件

image.png

文件内容是: org.springframework.web.SpringServletContainerInitializer
3、SpringServletContainerInitializer 将 handlerTypes 标注的所有类型的类传入到 onStartip 方法的 Set<Class<?>> 中,并为这些感兴趣类创建实例
4、每个创建好的 WebApplicationInitializer 调用自己的 onStratup
5、因为有下图所示的继承关系,我们编写的 ExternalServletInitializerSpringBootServletInitializer 都会被创建实例,并执行各自的 StartUp 方法,然而 ExternalServletInitializer 没有该方法,所以会调用其父类 SpringBootServletInitializer 的 onstartUp 方法。
image.png

6、SpringBootServletInitializer 执行 onStartup 方法会执行 createRootApplicationContext,在调用其中的 Configure 时,由于其子类 ExternalServletInitializer 重写了这个方法,所以会调用子类重写的这个方法,那么就会将 SpringBoot 的主程序类传入进来。

image.png

image.png

7、build SpringApplication 并启动;

image.png

6.4. 其他

https://www.bilibili.com/video/BV1gW411W76m?p=51&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204
嵌入式的 Servlet 容器:应用打成 jar 包
​ 优点:简单、便携
​ 缺点:默认不支持 JSP、优化定制比较复杂(使用定制器【ServerProperties、自定义定制器】,自己来编写嵌入式的容器工厂)

外置的 Servlet 容器:外面安装 Tomcat 是以 war 包的方式打包。
https://www.bilibili.com/video/BV1gW411W76m?p=52&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204

7. SpringBoot 的核心注解

1. @SpringBootApplication 注解:这个注解标识了一个 SpringBoot 工程,它实际上是另外三个注解的组合,这三个注解是:
① @SpringBootConfiguration :这个注解实际就是一个@Configuration,表示启动类也是一个配置类
② @EnableAutoConfiguration:向 Spring 容器中导入了一个 Selector,用来加载 ClassPath 下 SpringFactories 中所定义的自动配置类,将这些自动加载为配置 Bean  
③ @ComponentScan,但这个注解是 Spring 提供的
2.  @Conditional 也很关键,如果没有它我们无法在自定义应用中进行定制开发
@ConditionalOnBean、 
@ConditionalOnClass、
@ConditionalOnExpression、
@ConditionalOnMissingBean 等。

8. 为什么 SpringBoot 的 jar 可以直接运行⭐️🔴

%%
▶5.🏡⭐️◼️【fatjar, spring-boot-loader.jar, MANIFEST-MF, mainclass, jarlauncher, startclass】◼️⭐️-point-20230303-1616%%
^lf3ecs

8.1. spring-boot-maven-plugin 打 Fat jar

%%
▶5.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230305-0847%%
❕ ^s0yjgz

  1. SpringBoot 提供了一个插件 spring-boot-maven-plugin 用于把程序打包成一个可执行的 jar 包。

  2. SpringBoot 应用打包之后,生成一个 Fat jar(jar 包中包含 jar),包含了应用依赖的 jar 包和 Spring Boot loader 相关的类。❕%%
    ▶10.🏡⭐️◼️与自定义 starter 里的类 spring-boot-starter 类对比记忆◼️⭐️-point-20230302-1516%%

    image.png

如果我们要看 spring-boot-loader 源码,那么就需要自己引入依赖
image.png

8.2. MANIFEST.MF 文件

  1. java -jar 会去找 jar 中的 MANIFEST.MF 文件,在那里面找到真正的启动类(Main-Class),Fat jar 的启动 Main 函数是 JarLauncher,在 spring-boot-loader.jar

[[JVM源码分析之JVM启动流程_猿灯塔_InfoQ写作社区#^qwkqfc]]

image.png

在 JarLauncher 类中的 main 方法中有 launch 方法,进入之后有 2 个非常重要的方法: createClassLoaderlaunch
image.png

image.png

8.3. LaunchedURLClassLoader

  1. createClassLoader 负责创建一 LaunchedURLClassLoader加载 BOOT-INF\lib 下面的 jar
    image.png

image.png

8.4. launch

image.png

launch 负责以一个新线程启动应用的启动类的 Main 函数(找到 manifest 中的 Start-Class)

9. 自定义 starter⭐️🔴

%%
▶76.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230306-1507%%
📙❕ ^5tcs5g

https://www.bilibili.com/video/BV1Et411Y7tQ?p=70&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204

9.1. 使用场景⭐️🔴

在我们的日常开发工作中,经常会有一些独立于业务之外的配置模块,我们经常将其放到一个特定的包下,然后如果另一个工程需要复用这块功能的时候,只需要将其在 pom 中引用依赖即可,利用 SpringBoot 为我们完成自动装配即可。

常见的自定义 Starter 场景比如:

动态数据源
登录模块
基于 AOP 技术实现日志切面
%%
▶4.🏡⭐️◼️【🌈费曼无敌🌈⭐️♨️⭐️】◼️⭐️-point-20230315-0932%%
❕ ^xbsang

场景一:简化多服务公用框架集成- 封装 swagger 配置
众所周知,springboot 或者其他第三方所提供的 starter,都是做框架集成,通过简化配置,提高开发效率,所以我们自定义 starter 的第一个应用场景也是基于这个思路。那我们日常开发工作中,有哪些框架是多个服务共用的,并且 springboot 或者其他第三方暂未提供,或者嫌弃第三方写的太烂,想自己重新实现的,都可以通过编写自定义 starter 来简化工作。我们公司采用微服务架构,每个服务都会使用 swagger 来生成在线接口文档。未封装 swagger-starter 之前,那么在每个服务里边,都需要增加 swagger 的配置类。而封装 swagger-starter 之后,可以省去这一步的操作,还可以通过增加自定义配置来实现一些自定义的功能。比如我们公司安全部门要求生产环境不能对外开放 swagger 接口文档地址,那么我们就可以添加一个 enabled 的参数来代表 swagger 是否启用,默认启用,在生产环境的配置中将 enabled 设为 false 即可达到这个目的。类似的额外功能还有很多,比如增加请求头等等,其他的读者自行发掘。
上面提到的是业务无关性的 starter 应用场景,那么我们抛出一个问题,是否有业务相关且多个业务场景或者多个服务会使用的应用场景?根据这个问题的描述,我们至少可以列出以下几个业务相关场景。 服务治理-10、限流熔断降级(服务保护)-Sentinel
场景二:服务间调用的鉴权。
我们公司内部服务之间互相调用需要进行鉴权(还是安全部门的要求),由于服务间是通过 feign 来实现相互调用,所以无法通过网关来进行统一鉴权。实现方案是通过新增 feign 拦截器,==在源头服务发起调用之前增加鉴权参数,请求到达目标服务后通过鉴权参数进行鉴权==。这两步操作很明显是每个服务都需要的,那么这种情况下,我们就可以把这两步操作封装成 starter,达到简化开发的目的。同时,我们还可以通过增加配置,实现更细粒度的调用权限控制,比如订单服务只能调用库存服务的查询商品库存接口,而无法调用更新商品库存的接口。
场景三:邮件,短信,验证码功能。
这些功能,在某些公司可能会放在 common 包里,但是这样其实会导致 common 包的臃肿,因为并不是所有服务都会使用到。有些公司(还是我们公司)可能对邮件服务器的访问有严格权限控制的,而且权限开通流程比较繁复的,那么会考虑做成服务,部署在已经具有访问权限的主机上,减去重复申请权限工作。如果除去这些限制,那么将这些功能封装成 starter 还是挺不错的,可以避免 common 包的臃肿

9.2. 操作步骤

image.png

9.2.1. 确定场景需要使用依赖

9.2.2. 使用注解编写自动配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration //指定这个类是一个配置类
@ConditionalOnXXX //在指定条件下成立的情况下自动配置类生效
@AutoConfigureAfter //指定自动配置类的顺序
@Bean //给容器中添加组件

@ConfigurationProperties //结合相关xxxProperties类来绑定相关的配置
@EnableConfigurationProperties //让xxxProperties生效加到容器中

自动配置类要能加载
将需要启动就加载的自动配置类,配置在META-INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

image.png

9.2.3. 编写 2 个模块

%%
▶12.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230305-1118%%
❕ ^8m431i

  1. 启动器空的 jar 只需要做依赖管理导入;比如 xxx-spring-boot-starter,使用方只需要引入这个启动器即可
    image.png

  2. 专门写一个自动配置模块;比如 xxx-spring-boot-starter-autoconfigurer,所有的依赖项都放在这个模块的 META-INF/spring.factories 中,key 为 org.springframework.boot.autoconfigure.EnableAutoConfiguration
    同时 pom 中需要添加基础依赖 spring-boot-starter
    image.png

  3. 启动器依赖自动配置,别人只需要引入 starter
    xxx-spring-boot-starter
    %%
    ▶1.🏡⭐️◼️如果自定义 starter 中用到了属性信息 ?🔜MSTM📝 可以编写一个属性类,使用注解@ConfigurationProperties,然后使用 setter 方法或者构造导入的方法关联到 Service 类上,在 Configurer 类里直接注入使用◼️⭐️-point-20230226-0812%%

9.3. 与 common 包对比

  1. common 包不灵活,需要不需要的内容都在一个 common 包里,不需要的内容也随着 common 包引入到工程中
  2. 单个功能增加太多,common 包容易变的臃肿

9.4. 示例代码

[[SpringBoot-V1-入门简介#^u6byiq]]
[[pages/002-schdule/001-Arch/001-Subject/013-DemoCode/springboot2/boot-09-customer-starter/atguigu-hello-spring-boot-starter-autoconfigure/src/main/java/com/atguigu/hello/auto/HelloServiceAutoConfiguration.java]]

[[SpringBoot-V1-入门简介#8 1 新建一个 starter]]

10. 配置读取原理和优先级规则⭐️🔴

%%
▶7.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230303-1851%%
^uxezha

10.1. 读取原理

通过事件监听的方式读取的配置文件:ConfigFileApplicationListener
优先级从高到低,高优先级的配置覆盖低优先级的配置,所有配置会形成互补配置。
ConfigFileApplicationListener 会监听 onApplicationEnvironmentPreparedEvent 事件来加载配置文件 application.properties 的环境变量
image.png

10.2. 优先级规则

10.2.1. 文件优先级

10.2.1.1. 外部配置源

常用:properties 文件、YAML 文件、环境变量、命令行参数;

10.2.1.2. properties 优于 ymal

正常的情况是先加载 yml,接下来加载 properties 文件。如果相同的配置存在于两个文件中。最后会使用 properties 中的配置。最后读取的优先级最高。

两个配置文件中的端口号不一样会读取 properties 中的端口号

10.2.2. 查找覆盖优先级

配置文件查找位置:查找覆盖顺序:优先级逐级变高

        1. classpath 根路径
        2. classpath 根路径下 config 目录
        3. jar 包当前目录
        4. jar 包当前目录的 config 目录
        5. /config 子目录的直接子目录

10.2.3. 加载生效优先级

配置文件加载顺序:加载顺序:外部>内部、加 profile>不加 profile

        1.  当前 jar 包内部的 application.properties 和 application.yml
     2.  当前 jar 包内部的 application-{profile}.properties 和 application-{profile}.yml
     3. 引用的外部 jar 包的 application.properties 和 application.yml
     4. 引用的外部 jar 包的 application-{profile}.properties 和 application-{profile}.yml

10.2.4. 官方文档

https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config

image.png

指定环境优先,外部优先,后面的可以覆盖前面的同名配置项

10.2.5. 案例

image.png

11. SpringBoot 的默认日志实现框架及切换

https://www.bilibili.com/video/BV1mf4y1c7cV?p=82&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204

https://www.bilibili.com/video/BV1Et411Y7tQ?p=23&spm_id_from=pageDriver&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204
image.png

11.1. SpringBoot 日志框架

1. SpringBoot 底层使用 slf4j+logback 的方式进行日志记录
logback 桥接:logback-classic
2. SpringBoot 同时也把其他的日志都替换成了 slf4j;
a. log4j2 适配: log4j-over-slf4j   (默认提供了适配器,如果切换 log4j2 只需要更换场景启动器即可)
b. jul 适配:jul-to-slf4j 
c. jcl 适配:jcl-over-slf4j

11.2. 将 logback 切换成 log4j2

image.png

1. 将 logback 的场景启动器排除(slf4j 只能运行有 1 个桥接器)
2. 添加 log4j2 的场景启动器
3. 添加 log4j2 的配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- 排除掉logback的依赖-->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

<!-- 添加log4j2依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

11.3. 将 logback 切换成 log4j

1. 要将 logback 的桥接器排除

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>logback-classic</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
</exclusions>
</dependency>

2. 添加 log4j 的桥接器

1
2
3
4
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j‐log4j12</artifactId>
</dependency>

3. 添加 log4j 的配置文件

12. 容器

在 Web 环境中是由 Spring 和 SpringMvc 两个容器组成的,在 SpringBoot 环境中只有一个容器 AnnotationConfigEmbeddedWebApplicationContext。也就是可以说是由 SpringBoot 容器管理的。

12.1. 配置嵌入式 Servlet 容器

image.png

image.png

12.2. 嵌入式 Servlet 容器自动配置原理 v1⭐️🔴

%%
▶8.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230302-1057%%

https://www.bilibili.com/video/BV1Et411Y7tQ?p=48&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204
image.png ^17d8bq

12.2.1. 引入依赖触发自动配置

 当加入 Spring-boot-starter-web 场景启动器依赖时,@ConditionalOnWebApplication 注解会触发 EmbeddedServletContainerAutoConfiguration 自动配置类开启嵌入式 Servlet 容器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
//给容器导入组件 后置处理器 在Bean初始化前后执行前置后置的逻辑 创建完对象还没属性赋值进行初始化工作
public class EmbeddedServletContainerAutoConfiguration {
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class })//当前是否引入tomcat依赖
//判断当前容器没有用户自定义EmbeddedServletContainerFactory,就会创建默认的嵌入式容器
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {

@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory();
}

12.2.2. 创建默认的嵌入式容器 -EmbeddedServletContainerFactory

如果当前容器没有用户自定义 EmbeddedServletContainerFactory,就会创建一个默认的 TomcatEmbeddedServletContainerFactory,用来创建嵌入式容器,默认为 Tomcat,也支持其他嵌入式容器,3 种工厂分别可以创建 3 种 EmbeddedServletContainer,继承关系如下图所示:

24.EmdServletFactory

25.EmdServletContainer

以 TomcatEmbeddedServletContainerFactory 为例,new 了一个 Tomcat 出来并配置,然后传入 getTomcatEmbeddedServletContainer 方法,在该方法中会启动 Tomcat。SpringBoot2 中该方法名字为 getWebServer。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat();
//配置tomcat的基本环节
File baseDir = (this.baseDirectory != null ? this.baseDirectory
: createTempDir("tomcat"));
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
//将配置好的tomcat传入进去;并且启动tomcat容器
return getTomcatEmbeddedServletContainer(tomcat);
}

12.2.3. 嵌入式配置自动解析方式 -EmbeddedServletContainerCustomizerBeanPostProcessor

有 2 种方式:ServerProperties、EmbeddedServletContainerCustomizer

EmbeddedServletContainerCustomizer 自动应用 Servlet 容器配置原理
是通过 EmbeddedServletContainerCustomizerBeanPostProcessor 来完成的

容器在配置类 EmbeddedServletContainerAutoConfiguration 中通过 @Import(BeanPostProcessorsRegistrar.class) 导入了 EmbeddedServletContainerCustomizerBeanPostProcessor,在 postProcessBeforeInitialization 方法中,判断如果当前初始化的是一个 ConfigurableEmbeddedServletContainer,就会获取所有的定制器,调用每个定制器的 customer 方法给 Servlet 容器进行赋值。

BeanPostProcessorsRegistrar.registerBeanDefinitions

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if (this.beanFactory == null) {
return;
}
registerSyntheticBeanIfMissing(registry,
"embeddedServletContainerCustomizerBeanPostProcessor",
EmbeddedServletContainerCustomizerBeanPostProcessor.class);
registerSyntheticBeanIfMissing(registry,
"errorPageRegistrarBeanPostProcessor",
ErrorPageRegistrarBeanPostProcessor.class);
}

EmbeddedServletContainerCustomizerBeanPostProcessor.postProcessBeforeInitialization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
//如果当前初始化的是一个ConfigurableEmbeddedServletContainer
if (bean instanceof ConfigurableEmbeddedServletContainer) {
postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
}
return bean;
}

private void postProcessBeforeInitialization(
ConfigurableEmbeddedServletContainer bean) {
//获取所有的定制器,调用每个定制器的customer方法给Servlet容器进行赋值
for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {
customizer.customize(bean);
}
}

private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {
if (this.customizers == null) {
// Look up does not include the parent context
this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
this.beanFactory
//从容器中获取所有的这个类型的组件:EmbeddedServletContainerCustomizer
//定制Servlet,给容器中可以添加一个EmbeddedServletContainerCustomizer类型的组件
.getBeansOfType(EmbeddedServletContainerCustomizer.class,
false, false)
.values());
Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
this.customizers = Collections.unmodifiableList(this.customizers);
}
return this.customizers;
}

而 ServerProperties 也是 EmbeddedServletContainerCustomizer 实现类,所以也会被自动配置
image.png

12.2.4. 总结

1)、SpringBoot 根据导入的依赖情况,给容器中添加响应的容器工厂比如 tomcat
对应的 TomcatEmbeddedServletContainerFactory

2)、容器中某个组件要创建对象就要通过后置处理器;
EmbeddedServletContainerCustomizerBeanPostProcessor
只要是嵌入式的 Servlet 容器工厂,后置处理器就工作;

3)、后置处理器,从容器中获取的所有的 EmbeddedServletContainerCustomizer,调用定制器的定制方法

12.3. 定制化原理

  1. 修改配置文件;
  2. xxxxxCustomizer;
1
2
3
4
5
6
7
@Component
public class MyWebServerFactoryCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
@Override
public void customize(ConfigurableServletWebServerFactory server) {
server.setPort(9000);
}
}
  1. 编写自定义的配置类 xxxConfiguration;+ @Bean 替换、增加容器中默认组件;视图解析器
  2. Web 应用编写一个配置类实现 WebMvcConfigurer 即可定制化 web 功能;+ @Bean 给容器中再扩展一些组件
1
2
@Configuration
public class AdminWebConfig implements WebMvcConfigurer
  1. @EnableWebMvc + WebMvcConfigurer —— @Bean 可以全面接管 SpringMVC,所有规则全部自己重新配置;实现定制和扩展功能
    ○ 原理
    ○ 1、WebMvcAutoConfiguration 默认的 SpringMVC 的自动配置功能类。静态资源、欢迎页…..
    ○ 2、一旦使用 @EnableWebMvc 会@Import(DelegatingWebMvcConfiguration.class)
    ○ 3、DelegatingWebMvcConfiguration 的作用,只保证 SpringMVC 最基本的使用
    ■ 把所有系统中的 WebMvcConfigurer 拿过来。所有功能的定制都是这些 WebMvcConfigurer 合起来一起生效
    ■ 自动配置了一些非常底层的组件。RequestMappingHandlerMapping、这些组件依赖的组件都是从容器中获取
    ■ public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
    ○ 4、WebMvcAutoConfiguration 里面的配置要能生效必须 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
    ○ 5、@EnableWebMvc 导致了 WebMvcAutoConfiguration 没有生效。

13. Java Config

13.1. @Configuration(proxyBeanMethods = false)

lite 模式下,直接返回新实例对象,不用生成代理。

Spring 5.2.0+ 的版本,建议你的配置类均采用 Lite 模式去做,即显示设置 proxyBeanMethods = false。Spring Boot 在 2.2.0 版本(依赖于 Spring 5.2.0)起就把它的所有的自动配置类的此属性改为了 false,即@Configuration(proxyBeanMethods = false),目的是为了提高 Spring 启动速度

https://blog.csdn.net/yunxing323/article/details/108655250

13.2. @Import

image-20210921204122547

14. Rest 原理

14.1. filter+wrapper

image-20210921060612553
Rest 原理(表单提交要使用 REST 的时候)
● 表单提交会带上 _method=PUT
● 请求过来被 HiddenHttpMethodFilter 拦截
○ 请求是否正常,并且是 POST
■ 获取到 _method 的值。
■ 兼容以下请求;PUT、DELETE、PATCH
■ 原生 request(post),包装模式 requesWrapper 重写了 getMethod 方法,返回的是传入的值。
■ 过滤器链放行的时候用 wrapper。以后的方法调用 getMethod 是调用 requesWrapper 的。

image-20210921060523227

image.png

Rest 使用客户端工具,
● 如 PostMan 直接发送 Put、delete 等方式请求,无需 Filter,但要注意方式可用取值为 GET、PUT、DELETE、PATCH

14.2. 自定义隐藏域名称

1
2
3
4
5
6
7
//自定义filter
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
methodFilter.setMethodParam("_m");
return methodFilter;
}

15. 请求映射原理⭐️🔴

%%
▶1.🏡⭐️◼️【🌈费曼无敌🌈⭐️第一步⭐️】◼️⭐️-point-20230410-0835%%
❕ ^ijjhr0

https://www.bilibili.com/video/BV1Et411Y7tQ?p=139&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204

DispatchServlet

image-20210921061541902

15.1. 请求路径

HttpServlet.doGetFrameworkServlet.processRequestFrameworkServlet.doServiceDispatcherServlet.doServiceDispatcherServlet.doDispatch (每个请求都会调用这个方法)

15.2. 执行逻辑

15.2.1. handlerMappings

image-20211011085954656

image-20211011091433222

● 请求进来,挨个尝试所有的 HandlerMapping 看是否有请求信息。
○ 如果有就找到这个请求对应的 handler
○ 如果没有就是下一个 HandlerMapping

image-20211011090131565

15.2.2. RequestMappingHeaderMapping

保存了所有@RequestMapping 和对应 handler 的所有映射关系

image-20211011090316527

15.2.3. 获取 handler 逻辑

15.2.4. mappingRegistry

image-20211011090316527

image-20211011090729432

16. 其他

16.1. jar 包引入方式

https://cloud.tencent.com/developer/article/1500334

16.1.1. spring-boot-starter-parent

16.1.2. spring-boot-dependencies

https://blog.csdn.net/haohao_g/article/details/99695535

使用场景:可能有自己的企业标准 parent

或者你可能只是比较喜欢明确声明所有的 Maven 配置

16.2. 多继承问题

https://www.jianshu.com/p/7145f01ac3ad

16.3. dependencyManagement

dependencyManagement 节点的作用是统一 maven 引入依赖 JAR 包的版本号,可以看出 spring-boot-dependencies 最重要的一个作用就是对 springboot 可能用到的依赖 JAR 包做了版本号的控制管理

17. 与 Spring 的不同之处

17.1. 动态代理

  1. Spring 是动态选择的,有接口就用 JDK 动态代理,否则使用 cglib 动态代理
    可以通过 exproxy-target-class1、Spring-基础
  2. SpringBoot 默认是 cglib 动态代理

17.2. SpringMVC 容器⭐️🔴

  1. Spring 集成 SpringMVC 是通过 SPI 方式注册子容器来实现集成
  2. SpringBoot 通过@Bean 注册了 DispatcherServlet,并没有像 Spring 集成 SpringMVC 中那样,通过 SPI 的方式创建子容器

18. 参考与感谢

18.1. SpringBoot

18.1.1. 视频

01、P112–P198 为雷神 2021 版 springboot2 教程 <– 建议直接看新版 02、2021 版直达链接: https://www.bilibili.com/video/BV1Et411Y7tQ?p=112&spm_id_from=333.788.b_636f6d6d656e74.4
/Volumes/Seagate Bas/001-ArchitectureRoad/尚硅谷 Springboot 经典版(核心技术 and 整合篇)/核心技术篇/视频 3/视频 3 ^yfxc8z

18.1.2. 代码

/Users/taylor/Nutstore Files/Obsidian_data/pages/002-schdule/001-Arch/001-Subject/013-DemoCode/SpringBoot

18.1.3. 笔记

/Users/taylor/Nutstore Files/Obsidian_data/pages/002-schdule/001-Arch/001-Subject/002- 框架源码专题/000-Spring/SpringBoot
[[SpringBoot]]

18.2. SpringBoot2

18.2.1. 视频

https://www.bilibili.com/video/BV19K4y1L7MT?p=58&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204

18.2.2. 笔记

语雀: https://www.yuque.com/atguigu/springboot

18.2.3. 代码

/Users/taylor/Nutstore Files/Obsidian_data/pages/002-schdule/001-Arch/001-Subject/013-DemoCode/springboot2

18.3. 汇总

01、P112–P198 为雷神 2021 版 springboot2 教程 <– 建议直接看新版 02、2021 版直达链接: https://www.bilibili.com/video/BV1Et411Y7tQ?p=112&spm_id_from=333.788.b_636f6d6d656e74.4


2021 版配套笔记及源码:
配套源码 - 雷神码云地址: https://gitee.com/leifengyang/springboot2
配套笔记 - 语雀地址: https://yuque.com/atguigu/springboot


旧版配套源码、文档等:
尚硅谷 springboot 核心篇 + 整合篇配套资料
链接: https://pan.baidu.com/s/1Yfv05ncJoP_gOHB6cm9jdg 提取码: 9h5i

18.4. 其他

https://www.bilibili.com/video/BV1zh411H79h?p=4

18.5. Spring

1、Spring-基础

18.6. 黑马⭐️🔴✅

18.6.1. 视频

https://www.bilibili.com/video/BV15b4y1a7yG?p=169&spm_id_from=pageDriver&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204

18.6.2. 资料

1
/Users/taylor/Nutstore Files/Obsidian_data/pages/002-schdule/001-Arch/001-Subject/002-框架源码专题/000-Spring/SpringBoot/原理篇-资料