SpringBoot启动原理
运行main方法,创建SpringApplication,从spring.factories中读取Listener、ApplicationContextInitializer,创建SpringApplication的作用如下
- 将启动类放入到primarySources里面(注册启动类)
- 推算当前的web应用类型webApplicationType
- 读取ApplicationListener监听器
- 将main方法所在的类放入mainApplication(将当前的类作为配置类)
run方法启动,加载IOC容器
SpringBoot自动配置原理
- 通过@SpringBootApplication注解引入@EnableAutoConfiguration实现自动配置功能
- @EnableAutoConfiguration引入@Import,Spring容器启动时,加载Ioc容器会去解析@Import
- @Import导入一个deferredImportSelector,这个对象使SpringBoot的自动配置类加载顺序排在最后,方便扩展和覆盖操作(因为在自动配置类的上面通常会使用Condition注解来对类的加载条件进行限定,所以需要将他的加载顺序排在最后,等前面的东西都准备好)
- 读取/META-INF/spring.factories文件,过滤出所有AutoConfigurationClass类型的类,通过Condition注解对配置类进行过滤,加载
SpringBoot的jar为什么可以直接运行
- SpringBoot提供了一个插件spring-boot-maven-plugin用于把程序打包成一个可执行的jar包
- SpringBoot项目打包之后,生成一个Fat jar(jar中包含了jar),包含了应用依赖的jar包和SpringBoot loader相关的类
- java -jar会去找jar中的mainifest文件,这是一个配置文件,里面配置了加载jar的加载器(Main-Class)和初始的启动类(Start-Class)
- Fat jar的启动Main函数是JarLauncher,它负责创建一个LaunchedURLClassLoader来加载boot-lib下的jar,并以一个新线程启动应用(Start-Class)
SpringBoot可以同时处理多少请求
可以通过配置SpringBoot内嵌服务器tomcat的max-connections(最大连接数)和accept-count(最大等待数)这两个属性来控制请求的数量,可以同时处理的请求数量等于这两个属性的值相加,max-connections默认8192,accept-count默认100
另外两个比较有关系的参数就是threads.min-spre(最小工作线程数)和threads.max(最大工作线程数)
SpringBoot如何优化启动速度
SpringBoot在云原生时代下的优化方向:
- 启动速度快
- 占用资源少
- 打包体积小
优化启动速度方式
- 延迟初始化Bean:一些比较耗时间的操作,如建立数据库连接,初始化线程池,可以延迟加载,Spring2.2之后将spring.main.lazy-initialization设置为true会将所有Bean延迟初始化
- 创建扫描索引:Spring5之后提供了spring-context-indexer功能,可以通过在编译时创建一个静态候选列表来提高大型应用程序的启动速度。配置方式为引入spring-context-indexer依赖,启动类上加上@Indexed注解,编译打包的时候在META-INF/spring-conponents文件中会将我们要加载的Bean按照一定的顺序排列好,按照顺序加载Bean可以提高一定的速度。
- 升级JDK17:性能更加好的垃圾回收器
- 升级SpringBoot3:spring-graalvm-native支持使用GraalVM将SpringBoot的应用程序编译成可执行的镜像文件,可以提高启动速度,峰值性能和减少内存占用
- 控制扫描包的范围
- 关闭SpringBoot的JMX监控,设置spring.jmx.enabled=false
- 设置JVM参数-noverify,不对类进行验证
- 排除多余的依赖
重点在于3和4两个方法
SpringBoot解决跨域问题
跨域:域名、协议、端口、ip不同
JSONP:前端在向后端发送请求的时候添加上特定的参数,后端响应时将参数原路返回,相当于在前后端交互之间建立起一个信任的基石,前端代码

后端代码:
JSONP的好处是兼容性好,缺点是只支持get,而且有安全问题,前后端存在耦合问题CORS:只需要在后端编写相应代码即可,缺点是一些老版本的浏览器可能不支持
- 使用@CrossOrigin解决单个接口的跨域问题

- 批量解决接口的跨域问题

- CorsFilter解决所有接口的跨域问题

- 使用@CrossOrigin解决单个接口的跨域问题
Nginx反向代理
SpringBoot读取配置文件的方式
- @Value单个配置属性:
@Value(${属性})- 注入的地方必须是个Bean
- 属性在配置文件中必须有,或者设置默认值:
@Value(${属性:默认值}) - static和final无法生效
- @ConfigurationProperties批量配置属性:
@ConfigurationProperties(prefix="属性前缀") - Environment对象获取两种方式

- 比较灵活的方式,适合开发组件

- 引入外部properties文件

- 获取外部yml文件

- 输入流方式

为什么SpringBoot使用CGLib作为默认的动态代理
- JDK动态代理代理的对象是接口,如果使用JDK动态代理的话,无法获取实现类上面的注解
- 在需要注入Bean的场合中,如果是CGLib动态代理,可以使用接口或者实现类来接收Bean对象
SpringBoot核心注解
- SpringBootApplication注解:标识一个SpringBoot工程,由三个注解组成(@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan)
- @SpringBootConfiguration:实际上是一个@Configuration,表明启动类是一个配置类
- @EnableAutoConfiguration
- @Conditional:定制化开发需要的注解
- @ConditionalOnBean
- @ConditionalOnMissingBean
- @ConditionalOnClass
- @ConditionalOnMissingClass
- @ConditionalOnExpression
SpringBoot内置Tomcat启动原理
- 添加spring-boot-starter-web依赖后会在SpringBoot中添加:ServletWebServerFactoryAutoConfiguration的servlet容器自动配置类
- 该自动配置类通过@Import导入可用的一个Web容器工厂,使用@Conditional的注解判断使用什么类型的服务器,默认Tomcat
- 在内嵌Tomcat类中配置了一个TomcatServletWebServerFactory的Bean(Web容器工厂)
- 在SpringBoot启动时,refresh方法加载Ioc容器,onfresh方法创建内嵌的Tomcat并启动,后调用Tomcat的await方法等待请求
参考资料: