SpringBoot

shuyepl 2024-01-21 15:13:50
Categories: Tags:

SpringBoot启动原理

运行main方法,创建SpringApplication,从spring.factories中读取Listener、ApplicationContextInitializer,创建SpringApplication的作用如下

run方法启动,加载IOC容器

SpringBoot自动配置原理

  1. 通过@SpringBootApplication注解引入@EnableAutoConfiguration实现自动配置功能
  2. @EnableAutoConfiguration引入@Import,Spring容器启动时,加载Ioc容器会去解析@Import
  3. @Import导入一个deferredImportSelector,这个对象使SpringBoot的自动配置类加载顺序排在最后,方便扩展和覆盖操作(因为在自动配置类的上面通常会使用Condition注解来对类的加载条件进行限定,所以需要将他的加载顺序排在最后,等前面的东西都准备好)
  4. 读取/META-INF/spring.factories文件,过滤出所有AutoConfigurationClass类型的类,通过Condition注解对配置类进行过滤,加载

SpringBoot的jar为什么可以直接运行

  1. SpringBoot提供了一个插件spring-boot-maven-plugin用于把程序打包成一个可执行的jar包
  2. SpringBoot项目打包之后,生成一个Fat jar(jar中包含了jar),包含了应用依赖的jar包和SpringBoot loader相关的类
  3. java -jar会去找jar中的mainifest文件,这是一个配置文件,里面配置了加载jar的加载器(Main-Class)和初始的启动类(Start-Class)
  4. 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在云原生时代下的优化方向:

优化启动速度方式

  1. 延迟初始化Bean:一些比较耗时间的操作,如建立数据库连接,初始化线程池,可以延迟加载,Spring2.2之后将spring.main.lazy-initialization设置为true会将所有Bean延迟初始化
  2. 创建扫描索引:Spring5之后提供了spring-context-indexer功能,可以通过在编译时创建一个静态候选列表来提高大型应用程序的启动速度。配置方式为引入spring-context-indexer依赖,启动类上加上@Indexed注解,编译打包的时候在META-INF/spring-conponents文件中会将我们要加载的Bean按照一定的顺序排列好,按照顺序加载Bean可以提高一定的速度。
  3. 升级JDK17:性能更加好的垃圾回收器
  4. 升级SpringBoot3:spring-graalvm-native支持使用GraalVM将SpringBoot的应用程序编译成可执行的镜像文件,可以提高启动速度,峰值性能和减少内存占用
  5. 控制扫描包的范围
  6. 关闭SpringBoot的JMX监控,设置spring.jmx.enabled=false
  7. 设置JVM参数-noverify,不对类进行验证
  8. 排除多余的依赖

重点在于3和4两个方法

SpringBoot解决跨域问题

跨域:域名、协议、端口、ip不同

  1. JSONP:前端在向后端发送请求的时候添加上特定的参数,后端响应时将参数原路返回,相当于在前后端交互之间建立起一个信任的基石,前端代码image-20240122155627828

    后端代码:image-20240122155821788JSONP的好处是兼容性好,缺点是只支持get,而且有安全问题,前后端存在耦合问题

  2. CORS:只需要在后端编写相应代码即可,缺点是一些老版本的浏览器可能不支持

    1. 使用@CrossOrigin解决单个接口的跨域问题image-20240122160116330
    2. 批量解决接口的跨域问题image-20240122160311296
    3. CorsFilter解决所有接口的跨域问题image-20240122160429118
  3. Nginx反向代理

SpringBoot读取配置文件的方式

  1. @Value单个配置属性:@Value(${属性})
    1. 注入的地方必须是个Bean
    2. 属性在配置文件中必须有,或者设置默认值:@Value(${属性:默认值})
    3. static和final无法生效
  2. @ConfigurationProperties批量配置属性:@ConfigurationProperties(prefix="属性前缀")
  3. Environment对象获取两种方式
    1. image-20240122162359478
    2. 比较灵活的方式,适合开发组件image-20240122162524814
  4. 引入外部properties文件image-20240122162711915
  5. 获取外部yml文件image-20240122162854437
  6. 输入流方式image-20240122163140084

为什么SpringBoot使用CGLib作为默认的动态代理

SpringBoot核心注解

  1. SpringBootApplication注解:标识一个SpringBoot工程,由三个注解组成(@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan)
  2. @SpringBootConfiguration:实际上是一个@Configuration,表明启动类是一个配置类
  3. @EnableAutoConfiguration
  4. @Conditional:定制化开发需要的注解
    1. @ConditionalOnBean
    2. @ConditionalOnMissingBean
    3. @ConditionalOnClass
    4. @ConditionalOnMissingClass
    5. @ConditionalOnExpression

SpringBoot内置Tomcat启动原理

  1. 添加spring-boot-starter-web依赖后会在SpringBoot中添加:ServletWebServerFactoryAutoConfiguration的servlet容器自动配置类
  2. 该自动配置类通过@Import导入可用的一个Web容器工厂,使用@Conditional的注解判断使用什么类型的服务器,默认Tomcat
  3. 在内嵌Tomcat类中配置了一个TomcatServletWebServerFactory的Bean(Web容器工厂)
  4. 在SpringBoot启动时,refresh方法加载Ioc容器,onfresh方法创建内嵌的Tomcat并启动,后调用Tomcat的await方法等待请求

参考资料: