文章目录
- Spring和SpringBoot的区别 ?
- 讲一讲SpringBoot自动装配的原理👍
- 讲一讲SpringBoot启动流程
- 你们常用的Starter有哪些👍
- 如何定义一个SpringBoot的starter 👍
- SpringBoot支持的配置文件有哪些👍
- 讲一讲SpringBoot项目配置文件的加载顺序👍
- SpringBoot的核心注解是哪个?👍
- Spring Boot 中如何解决跨域问题👍
- SpringBoot项目如何实现配置的热更新 ? 👍
- springboot打出来的jar包跟普通的jar包有什么区别
更多相关内容可查看
Spring和SpringBoot的区别 ?
Spring是一个开源容器框架, 其核心就是控制反转 (IOC),和面向切面 (AOP), 简单的说就是一个分层的轻量级开源框架
Spring Boot它是一个基于Spring的快速开发框架,可以帮助开发者快速构建基于Spring的应用程序
SpringBoot的核心就是 自动配置 和 依赖版本管理
讲一讲SpringBoot自动装配的原理👍
在SpringBoot项目的启动引导类上都有一个注解@SpringBootApplication
这个注解是一个复合注解, 其中有三个注解构成 , 分别是
- @SpringBootConfiguration : 是@Configuration的派生注解 , 标注当前类是一个SpringBoot的配置类
- @ComponentScan : 开启组件扫描, 默认扫描的是当前启动引导了所在包以及子包
- @EnableAutoConfiguration : 开启自动配置(自动配置核心注解)
在@EnableAutoConfiguration注解的内容使用@Import注解导入了一个AutoConfigurationImportSelector.class的类
在AutoConfigurationImportSelector.class中的selectImports方法内通过一系列的方法调用, 最终需要加载类加载路径下META-INF下面的spring.factories配置文件
在META-INF/spring.factories配置文件中, 定义了很多的自动配置类的完全限定路径
这些配置类都会被加载
加载配置类之后, 会配置类或者配置方法上的@ConditionalOnXxxx条件化注解是否满足条件
如果满足条件就会使用@ConfigurationProperties
注解从属性配置类中读取相关配置 , 执行配置类中的配置方法 , 完成自动配置
讲一讲SpringBoot启动流程
SpringBoot项目启动都会执行一个main方法 , main方法中调用SpringApplication.run()
方法启动程序 , 整个应用启动包括二部分 , 首先先构建SpringApplication
对象, 然后执行run
方法
构造SpringApplication的时候会进行初始化的工作,初始化的时候会做以下几件事:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
Assert.notNull(primarySources, "PrimarySources must not be null");
//1. 把primarySources设置到SpringApplication属性中 , 这个primarySources就是启动引导类字节码
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
//2. 判断是否是web程序,并设置到webEnvironment的boolean属性中
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//3. 创建并初始化ApplicationInitializer,设置到initializers属性中
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//4. 创建并初始化ApplicationListener,设置到listeners属性中
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//5. 初始化主类mainApplicatioClass
this.mainApplicationClass = this.deduceMainApplicationClass();
}
- SpringApplication构造完成之后调用run方法,启动SpringApplication,run方法执行的时候会做以下几件事:
public ConfigurableApplicationContext run(String... args) {
//1. 构造一个StopWatch计时器,用来记录SpringBoot的启动时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
//2. 初始化监听器,获取SpringApplicationRunListeners并启动监听,用于监听run方法的执行
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
//3. 创建并初始化ApplicationArguments,获取run方法传递的args参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//4. 创建并初始化ConfigurableEnvironment(环境配置)
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
//5. 打印banner和版本
Banner printedBanner = this.printBanner(environment);
//6. 构造Spring容器(ApplicationContext)上下文 , 发布上下文初始化事件(通知监听器执行)
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
//7. 准备Spring容器 , 将环境变量 , 监听器 , 应用参数注册到容器中
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//8. 刷新上下文 , 自动装配和启动 tomcat就是在这个方法里面完成的
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
//9. StopWatch计时器停止计时,日志打印总共启动的时间
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
//10. 发布SpringBoot程序已启动事件
listeners.started(context);
//11. 执行自定义的run方法 , 主要就是通知ApplicationRunner 和 CommandLineRunner 接口中的run方法执行
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
//最后发布就绪事件ApplicationReadyEvent,标志着SpringBoot可以处理就收的请求了
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
你们常用的Starter有哪些👍
常用的Starter有很多 , 例如 :
- spring-boot-starter-web
- spring-boot-starter-jdbc
- mybatis-spring-boot-starter
- spring-boot-starter-test
- mybatis-plus-spring-boot-starter
- spring-boot-starter-data-redis
- spring-boot-starter-data-elasticsearch
- spring-boot-starter-data-mongodb
- spring-boot-starter-amqp
- spring-cloud-starter-openfeign
- spring-cloud-starter-alibaba-nacos-discovery
如何定义一个SpringBoot的starter 👍
我们项目中其实也有自定义Starter , 主要用于封装一些复杂的操作, 让开发更加高效简单 , 我们项目中主要做的Starter主要包括 :
- 阿里云OSS的Starter
- 阿里云内容安全服务的Starter
- Minio的Starter
- 聚合支付的Starter
- EMQX的Starter
自己定义Starter也不难 , 我们在做的过程中 , 首先会梳理清楚这个Starter的核心功能和作用 , 将一些核心的操作封装为方法 , 封装到一个模板类中, 例如 : AliyunOssTempalte
,AliyunGreenTempalte
,MinioTemplate
之类的 , 这个过程其实比较麻烦
然后就抽取一些经常会变化的配置内容 , 例如 : 一些基本的连接地址配置 , 密钥配置等 , 提供属性配置类(XxxProperties) , 通过@ConfigurationProperties
注解读取配置文件到配置类
之后就创建一个自动配置类 , 在自动配置类中配置starter运行需要的一些基本配置 , 例如 : 连接工厂配置, 客户端对象配置 , 一些需要的Bean的配置 以及 需要用到的模板对象配置等 , 设置好生效条件@ConditionalOnXxx
最后就是在项目类加载路径下创建spring.factories
配置文件 , 在配置文件中配置自动配置类的全路径就可以了
Starter封装好了之后, 后期项目中使用只需要引入Starter依赖 , 在配置文件中配置所需要的信息 , 就能够完成自动配置 , 注入模板类就能够使用了
SpringBoot支持的配置文件有哪些👍
springboot支持二种类型的配置文件
- properties属性配置文件
- yaml配置文件
配置文件必须放置在项目的类加载目录下, 并且名字必须是application
springboot项目在运行的时候会自动加载这些配置文件
还有一种是引导配置文件 , 名字叫bootstrap
, 类型可以是properties
也可以是yaml
, 他会在application
配置文件之前加载, 一般用于读取配置中心相关信息
讲一讲SpringBoot项目配置文件的加载顺序👍
SpringBoot项目的配置形式有很多种 , 如下所示 :
- 外部配置中心配置 , 例如
spring cloud config
和Nacos
中的配置 - 命令行参数配置
- 操作系统环境变量配置
- 通过
spring.config.location
参数指定的配置文件 - 配置文件(YAML文件、Properties 文件) , Properties配置优先级高于YAML
- @Configuration 注解类上的 @PropertySource 指定的配置文件
以上所有形式的配置都会被加载 , 优先级由高到低,当存在相同配置内容时,高优先级的配置会覆盖低优先级的配置;存在不同的配置内容时,高优先级和低优先级的配置内容取并集,共同生效,形成互补配置
SpringBoot的核心注解是哪个?👍
Spring Boot的核心注解是@SpringBootApplication , 他由几个注解组成 :
- @SpringBootConfiguration: 组合了- @Configuration注解,实现配置文件的功能
- @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项
- @ComponentScan:Spring组件扫描 , 默认扫描启动引导类所在包以及子包
Spring Boot 中如何解决跨域问题👍
SpringMVC项目中使用@CrossOrigin注解来解决跨域问题 , 本质是CORS
@RequestMapping("/hello")
@CrossOrigin(origins = "*")
//@CrossOrigin(value = "http://localhost:8081") //指定具体ip允许跨域
public String hello() {
return "hello world";
}
SpringBoot项目采用自动配置的方式来配置CORS , 可以通过实现 WebMvcConfigurer接口然后重写addCorsMappings方法解决跨域问题。
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
//是否发送Cookie
.allowCredentials(true)
//放行哪些原始域
.allowedOrigins("*")
.allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
.allowedHeaders("*")
.exposedHeaders("*");
}
}
在SpringCloud项目中一般都会有网关 , 在网关中可以配置CORS跨域, 这样所有通过网关的请求都解决了跨域问题
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]': # 匹配所有请求
allowedOrigins: "*" #跨域处理 允许所有的域
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
SpringBoot项目如何实现配置的热更新 ? 👍
SpringBoot项目读取配置文件常用的方式有二种 :
- 通过@Value注解通过属性名称读取
- 通过@ConfigurationProperties属性 , 批量读取配置文件配置到属性配置类
实现热更新的方式也有二种 :
- @Value + @RefreshScope注解实现热更新
- 通过@ConfigurationProperties注解读取的属性, 自动会热更新
springboot打出来的jar包跟普通的jar包有什么区别
Spring Boot 打包出来的 JAR 包与普通的 JAR 包在一些方面有所不同,这些差异主要体现在以下几个方面:
- 嵌入式容器: Spring Boot 的 JAR 包包含一个的 Servlet 容器(如Tomcat、Jetty、Undertow等),这意味着你可以直接运行 JAR 包而不需要外部容器。
- 可执行性: Spring Boot 打包出来的 JAR 包通常是可执行的,这意味着你可以直接通过命令行或脚本来运行它。这对于部署和运维来说非常方便,因为你只需将 JAR 包传输到目标服务器上,并通过命令即可启动应用程序。
- Fat JAR: Spring Boot 打包出来的 JAR 包通常是 Fat JAR,也就是说它包含了所有的依赖库和资源文件。这样一来,你就不需要手动管理类路径和依赖了,应用程序的部署和运行也更加简单。
总的来说,Spring Boot 打包出来的 JAR 包具有更高的集成性、自动化程度和可执行性,使得开发、部署和运维过程更加简单和高效。