https://www.bilibili.com/video/BV1JX4y1P71J?t=33.2

SpringBoot

概述

谈谈你对SpringBoot的理解

在学SpringBoot之前我们肯定已经学过了spring、SpringMvc、Mybatis等框架了。使用整合这三个框架的方式去开发我们的代码比我们直接使用原生的Servlet去做Web开发更方便,在体验到SSM框架带来的好处的同时,我们也在为使用SSM框架开发之前要写一大堆的配置文件而苦恼,毕竟将这些东西都整合在一起不容易。也就是说我们做Spring Web项目开发之前要做的步骤包括但不限于以下步骤:

  • 配置web.xml去加载Spring、SpringMvc等
  • 配置数据库连接、配置数据源
  • 读取配置文件
  • ……

要是一不小心配错了其中的某个步骤,或者打错了某个东西,相信经验丰富的人都有体验,排bug就能排到你发癫。
而且Spring这个大熔炉能容纳的东西可不仅仅是这些,还有很多其他的框架。但仅仅是整合SSM要写的配置文件就足以让人发狂,若是再加上其他框架,那才真正是配置地狱了。
为了解决每次进行Web应用开发之前都要自己手动写配置文件,也为在程序员整合其他框架的时候不再重复那些固定的配置步骤,浪费时间,为了提高程序员的开发效率,SpringBoot出现了。以前要手动写一大堆配置文件才能启动的项目,现在SpringBoot完全自动的帮我们配置好了,我们只需要创建一个SpringBoot项目,就可以启动了,再写一个请求方法,就能够直接访问该请求了。
所以说,SpringBoot主要用来简化使用Spring的难度和繁重的XML配置,它是Spring组件的一站式解决方案,采取了习惯优于配置的方法。通过.properties或者.yml文件替代了Spring繁杂的XML配置文件,同时支持@ImportResource注解加载XML配置。Spring Boot还提供了嵌入式HTTP服务器、命令行接口工具、多种插件等等,使得应用程序的测试和开发简单起来。
1635593645208.png
如上图所示,都是spring生态中的技术,比如Microservices(微服务开发),我们实际开发中随便一个web应用因为功能模块众多,它随时可能成长为一个大型应用;故我们不能将其功能模块都写在一个项目中,我们应该将其中的功能模块拆分为一个一个微小的功能模块,每一个小模块就被成为一个微服务。
Reactive响应式开发、Cloud分布式云开发、serverless无服务开发、EventDriven事件驱动、Batch批处理等。spring的生态圈不仅仅局限于图中所示模块,还有很多很多。 要程序员每次开发应用的时候都自己写一遍,显然是不太理智的。

运行 Spring Boot 有哪几种方式?

  • 用命令打包或者放到容器中运行
  • 用 Maven 插件运行
  • 直接执行 main 方法运行

    Starter启动器

    什么是Spring Boot Starter?

    Starters可以理解为场景启动器,每一个场景启动器都包含了某个场景中需要到的所有依赖jar包,只需要在项目里面引入这些starter,相关场景的所有依赖都会导入到项目中来,要用什么功能就导入什么场景的starter启动器,而不需要到处找示例代码和依赖包,在jar包管理上非常方便,最终实现一站式开发。

SpringBoot 常用的 Starter 有哪些?

1、 spring-boot-starter-web :提供 Spring MVC + 内嵌的 Tomcat 。
2、 spring-boot-starter-data-jpa :提供 Spring JPA + Hibernate 。
3、 spring-boot-starter-data-Redis :提供 Redis 。
4、 mybatis-spring-boot-starter :提供 MyBatis 。
5、 mybatis-spring-boot-starter 第三方的mybatis集成starter

SpringBoot Starter 的工作原理是什么?

SpringBoot 在启动的时候会干这几件事情:
1、 SpringBoot 在启动时会去依赖的 Starter 包中寻找 resources/META-INF/spring.factories 文件,然后根据文件中配置的 Jar 包去扫描项目所依赖的 Jar 包。
2、 根据 spring.factories 配置文件去加载 AutoConfigure 类
3、 根据 @Conditional 注解的条件,进行自动配置将 Bean 注入 Spring Context容器

总结一下,其实就是 SpringBoot 在启动的时候,按照约定去读取 SpringBoot Starter 的配置信息,再根据配置信息对资源进行初始化,并注入到 Spring 容器中。这样 SpringBoot 启动完毕后,就已经准备好了一切资源,使用过程中直接注入对应 Bean 资源即可。

配置文件

SpringBoot 的核心配置文件有哪几个?它们的区别是什么?

SpringBoot 的核心配置文件是 application 和 bootstrap 配置文件
application 配置文件这个容易理解,主要用于 SpringBoot 项目的自动化配置。
bootstrap比 applicaton 优先加载,配置在应用程序上下文的引导阶段生效, 而且boostrap 里面的属性不能被覆盖;bootstrap 配置文件有以下几个应用场景:
使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;
一些固定的不能被覆盖的属性;
一些加密/解密的场景;

Spring Boot 的配置文件有哪几种格式?它们有什么区别?

YAML 是一种可读的数据序列化语言,它通常用于配置文件。
主要有.properties 和 .yml格式,它们的区别主要是书写格式不同。另外,.yml 格式不支持 @PropertySource 注解导入配置。

YAML 配置的优势在哪里 ?

配置有序
支持数组,数组中的元素可以是基本数据类型或者对象
简洁方便

Spring Boot 是否可以使用 XML 配置 ?

Spring Boot 推荐使用 Java 配置同时支持 XML 配置,通过 @ImportResource 注解加载 XML 配置。

什么是 Spring Profiles?

Spring Profiles 允许用户根据配置文件(dev,prod,test等等)来注册 bean。当应用程序在开发环境中运行时,只有某些 bean 可以加载,而在生产环境中,某些其他 bean 也可以加载。比如要求 Swagger 文档仅适用于测试环境,并且禁用所有其他文档,可以使用配置文件来完成。

SpringBoot 配置文件的加载位置以及优先级是什么

项目内部配置文件加载顺序

spring boot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件,如下图所示

  1. file:./config/
  2. file:./
  3. classpath:/config/
  4. classpath:/

image.png
SpringBoot会从这四个位置按照优先级从高到低(1-4)的顺序全部加载主配置文件,如果高优先级中配置文件属性与低优先级配置文件不冲突的属性,则会共同存在,互补配置;若是冲突的话高优先级配置内容会覆盖低优先级配置内容。
我们也可以通过配置spring.config.location来改变默认配置。

  1. java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=D:/application.properties

Spring Boot配置加载顺序优先级是:propertiese文件、YAML文件、系统环境变量、命令行参数。

Spring Boot 有哪几种读取配置的方式?

使用@Value注解加载单个属性值
使用@ConfigurationProperties注解可以加载一组属性的值,针对于要加载的属性过多的情况,比@Value注解更加简洁

自动配置

什么是自动配置?

Spring 和 SpringMVC 的问题在于需要配置大量的参数以及配置文件。
我们能否带来更多的智能?当一个 MVC JAR 添加到应用程序中的时候,我们能否自动配置一些 beans?
Spring 查看(CLASSPATH 上可用的框架)已存在的应用程序的配置。在此基础上,SpringBoot 提供了配置应用程序和框架所需要的基本配置。这就是自动配置。

Spring Boot 自动配置原理是什么?

@EnableAutoConfiguration注解、 @Configuration注解和 @ConditionalOnClass注解组成了Spring Boot自动配置的核心,SpringBoot启动的时候通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中所有的自动配置类,并对其进行加载,而这些自动配置类的类名都是以AutoConfiguration结尾来命名的,它实际上就是一个javaConfig形式的Spring容器配置类,它们都有一个@EnableConfigurationPerperties的注解,通过这个注解启动XXXProperties命名的类去加载全局配置中的属性,如server.port,而XXXProperties通过@ConfigurationProperties注解将全局配置文件中的属性与自己的属性进行绑定。

如何不通过任何配置来选择 Hibernate 作为 JPA 的默认实现?

因为 SpringBoot 是自动配置的。

下面是我们添加的依赖项:
spring-boot-stater-data-jpa 对于 Hibernate 和 JPA 有过渡依赖性。
当 SpringBoot 在类路径中检测到 Hibernate 时,将会自动配置它为默认的 JPA 实现。

SpringBoot核心注解

(Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的)介绍一下

@SpringBootApplication 注解

Spring Boot 的核心注解是@SpringBootApplication,它也是启动类使用的注解,主要包含了 3 个注解:
@SpringBootConfiguration:它组合了 @Configuration 注解,实现配置文件的功能。
@EnableAutoConfiguration:具有打开自动配置的功能,也可以关闭某个自动配置的选项。
@ComponentScan:用于Spring组件扫描。

嵌入式Web容器

Spring Boot支持哪些嵌入式Web容器?

Spring Boot支持的嵌入式servlet容器有: Tomcat、Jetty、Undertow。

日志相关

Spring Boot 支持哪些日志框架?推荐和默认的日志框架是哪个?

Spring Boot 支持 Java Util Logging, Log4j2, Logback 作为日志框架,如果使用 Starters 启动器,Spring Boot 将使用 Logback 作为默认日志框架,推荐的日志框架是Log4j2。

SpringBoot如何配置log4j?

在创建Spring Boot工程时,我们引入了spring-boot-starter,其中包含了spring-boot-starter-logging,该依赖的默认实现内容就是Spring Boot默认的日志框架Logback,所以我们在引入log4j之前,需要先排除该包的依赖,再引入log4j的依赖;

  1. <!-- 忽略自带的日志框架. -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter</artifactId>
  5. <exclusions>
  6. <exclusion>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-logging</artifactId>
  9. </exclusion>
  10. </exclusions>
  11. </dependency>
  12. <!-- log4j. -->
  13. <dependency>
  14. <groupId>org.springframework.boot</groupId>
  15. <artifactId>spring-boot-starter-log4j</artifactId>
  16. </dependency>

引入依赖之后,去src/main/resources目录下创建log4j-spring.properties配置文件,就可以开始对应用的日志进行配置使用。注意:Spring Boot官方推荐优先使用带有-spring的文件名作为你的日志配置(如使用log4j-spring.properties,而不是log4j.properties,不过取名为log4j.properties也是没有问题的)

log4j-spring.properties日志配置文件相关设置

  1. 1、控制台输出
  2. 通过如下配置,设定root日志的输出级别为INFOappender为控制台输出stdout
  3. # LOG4J配置
  4. log4j.rootCategory=INFO,stdout
  5. # 控制台输出
  6. log4j.appender.stdout=org.apache.log4j.ConsoleAppender
  7. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
  8. log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n
  9. 2、输出到文件
  10. 在开发环境,我们只是输出到控制台没有问题,但是到了生产或测试环境,或许持久化日志内容,方便追溯问题原因。可以通过添加如下的appender内容,按天输出到不同的文件中去,同时还需要为log4j.rootCategory添加名为fileappender,这样root日志就可以输出到logs/springboot.log文件中了。
  11. # LOG4J配置
  12. log4j.rootCategory=INFO,stdout,file
  13. # 日志输出到文件
  14. log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
  15. log4j.appender.file.file=logs/springboot.log
  16. log4j.appender.file.DatePattern='.'yyyy-MM-dd
  17. log4j.appender.file.layout=org.apache.log4j.PatternLayout
  18. log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n
  19. 当然输出到文件和输出到控制台是可以并行存在的。
  20. 3、分类输出
  21. 当我们日志量较多的时候,查找问题会非常困难,常用的手段就是对日志进行分类,比如:可以按不同package进行输出。通过定义输出到logs/my.logappender,并对com.didispace包下的日志级别设定为DEBUG级别、appender设置为输出到logs/my.log的名为didifileappender
  22. # com.kfit包下的日志配置
  23. log4j.category.com.kfit=DEBUG, didifile
  24. # com.didispace下的日志输出
  25. log4j.appender.didifile=org.apache.log4j.DailyRollingFileAppender
  26. log4j.appender.didifile.file=logs/my.log
  27. log4j.appender.didifile.DatePattern='.'yyyy-MM-dd
  28. log4j.appender.didifile.layout=org.apache.log4j.PatternLayout
  29. log4j.appender.didifile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L ---- %m%n
  30. 可以对不同级别进行分类,比如对ERROR级别输出到特定的日志文件中,具体配置可以如下:
  31. # LOG4J配置
  32. log4j.rootCategory=INFO, stdout,errorfile
  33. log4j.logger.error=errorfile
  34. # error日志输出
  35. log4j.appender.errorfile=org.apache.log4j.DailyRollingFileAppender
  36. log4j.appender.errorfile.file=logs/error.log
  37. log4j.appender.errorfile.DatePattern='.'yyyy-MM-dd
  38. log4j.appender.errorfile.Threshold = ERROR
  39. log4j.appender.errorfile.layout=org.apache.log4j.PatternLayout
  40. log4j.appender.errorfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n %5p %c{1}:%L - %m%n
  41. 4、输出到数据库
  42. 将日志文件输出到数据库配置:
  43. # LOG4J配置
  44. log4j.rootCategory=INFO,stdout,jdbc
  45. # 数据库输出
  46. log4j.appender.jdbc=org.apache.log4j.jdbc.JDBCAppender
  47. log4j.appender.jdbc.driver=com.mysql.jdbc.Driver
  48. log4j.appender.jdbc.URL=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=true
  49. log4j.appender.jdbc.user=root
  50. log4j.appender.jdbc.password=root
  51. log4j.appender.jdbc.sql=insert into log_icecoldmonitor(level,category,thread,time,location,note) values('%p','%c','%t','%d{yyyy-MM-dd HH:mm:ss:SSS}','%l','%m')

其他

Spring Boot 可以兼容老 Spring 项目吗?

可以兼容,使用 @ImportResource 注解导入老 Spring 项目配置文件。

Spring、SpringMVC、SpringBoot的区别?

1、 Spring框架就像一个家族,有众多衍生产品,例如boot、mvc、jpa等等。但他们的基础都是Spring的ioc、aop。ioc提供了依赖注入的容器,aop解决了面向横切面编程,然后在此两者的基础上实现了其它延伸产品的高级功能;
2、 springMVC是基于Servlet的一个MVC框架主要解决WEB开发的问题;
3、 为了简化开发的使用,从而创造性地推出了SpringBoot框架,默认优于配置

SpringBoot 中如何实现定时任务 ?

在 SpringBoot 中使用定时任务主要有两种不同的方式,一个就是使用 Spring 中的 @Scheduled 注解,另一-个则是使用第三方框架 Quartz。

使用 Spring 中的 @Scheduled 的方式主要通过 @Scheduled 注解来实现。

如何在SpringBoot中禁用Actuator端点安全性?

默认情况下,所有敏感的HTTP端点都是安全的,只有具有ACTUATOR角色的用户才能访问它们。

安全性是使用标准的HttpServletRequest.isUserInRole方法实施的。 我们可以使用management.security.enabled = false 来禁用安全性。只有在执行机构端点在防火墙后访问时,才建议禁用安全性。

如何在自定义端口上运行SpringBoot应用程序? 为了在自定义端口上运行SpringBoot应用程序,您可以在application.properties中指定端口。 server.port = 8090

Async异步调用方法

在SpringBoot中使用异步调用是很简单的,只需要在方法上使用@Async注解即可实现方法的异步调用。 注意:需要在启动类加入@EnableAsync使异步调用@Async注解生效。

什么是 WebSockets?

WebSocket 是一种计算机通信协议,通过单个 TCP 连接提供全双工通信信道。

1、 WebSocket 是双向的 -使用 WebSocket 客户端或服务器可以发起消息发送。

2、 WebSocket 是全双工的 -客户端和服务器通信是相互独立的。

3、 单个 TCP 连接 -初始连接使用 HTTP,然后将此连接升级到基于套接字的连接。然后这个单一连接用于所有未来的通信

4、 Light -与 http 相比,WebSocket 消息数据交换要轻得多。

我们如何监视所有 SpringBoot 微服务?

SpringBoot 提供监视器端点以监控各个微服务的度量。这些端点对于获取有关应用程序的信息(如它们是否已启动)以及它们的组件(如数据库等)是否正常运行很有帮助。但是,使用监视器的一个主要缺点或困难是,我们必须单独打开应用程序的知识点以了解其状态或健康状况。想象一下涉及 50 个应用程序的微服务,管理员将不得不击中所有 50 个应用程序的执行终端。为了帮助我们处理这种情况,我们将使用位于的开源项目。它建立在 SpringBoot Actuator 之上,它提供了一个 Web UI,使我们能够可视化多个应用程序的度量。

什么是 JavaConfig?

1、 面向对象的配置。由于配置被定义为 JavaConfig 中的类,因此用户可以充分利用 Java 中的面向对象功能。一个配置类可以继承另一个,重写它的@Bean 方法等。

2、 减少或消除 XML 配置。基于依赖注入原则的外化配置的好处已被证明。但是,许多开发人员不希望在 XML 和 Java 之间来回切换。JavaConfig 为开发人员提供了一种纯 Java 方法来配置与 XML 配置概念相似的 Spring 容器。从技术角度来讲,只使用 JavaConfig 配置类来配置容器是可行的,但实际上很多人认为将JavaConfig 与 XML 混合匹配是理想的。

3、 类型安全和重构友好。JavaConfig 提供了一种类型安全的方法来配置 Spring容器。由于 Java 5.0 对泛型的支持,现在可以按类型而不是按名称检索 bean,不需要任何强制转换或基于字符串的查找。

如何实现SpringBoot应用程序的安全性?

为了实现SpringBoot的安全性,我们使用 spring-boot-starter-security依赖项,并且必须添加安全配置。它只需要很少的代码。配置类将必须扩展WebSecurityConfigurerAdapter并覆盖其方法。

spring boot初始化环境变量流程?

1、 调用prepareEnvironment方法去设置环境变量

2、 接下来有三个方法getOrCreateEnvironment,configureEnvironment,environmentPrepared

3、 getOrCreateEnvironment去初始化系统环境变量

4、 configureEnvironment去初始化命令行参数

5、 environmentPrepared当广播到来的时候调用onApplicationEnvironmentPreparedEvent方法去使用postProcessEnvironment方法load yml和properties变量

比较一下 Spring Security 和 Shiro 各自的优缺点 ?

由于 SpringBoot 官方提供了大量的非常方便的开箱即用的 Starter ,包括 Spring Security 的 Starter ,使得在 SpringBoot 中使用 Spring Security 变得更加容易,甚至只需要添加一个依赖就可以保护所有的接口,所以,如果是 SpringBoot 项目,一般选择 Spring Security 。当然这只是一个建议的组合,单纯从技术上来说,无论怎么组合,都是没有问题的。Shiro 和 Spring Security 相比,主要有如下一些特点:

Spring Security 是一个重量级的安全管理框架;Shiro 则是一个轻量级的安全管理框架

Spring Security 概念复杂,配置繁琐;Shiro 概念简单、配置简单

Spring Security 功能强大;Shiro 功能简单

什么是 Apache Kafka?

Apache Kafka 是一个分布式发布 - 订阅消息系统。它是一个可扩展的,容错的发布 - 订阅消息系统,它使我们能够构建分布式应用程序。这是一个 Apache 顶级项目。Kafka 适合离线和在线消息消费。

spring-boot-starter-parent 有什么用 ?

我们都知道,新创建一个 SpringBoot 项目,默认都是有 parent 的,这个 parent 就是 spring-boot-starter-parent ,spring-boot-starter-parent 主要有如下作用:

1、 定义了 Java 编译版本为 1、8 。

2、 使用 UTF-8 格式编码。

3、 继承自 spring-boot-dependencies,这个里边定义了依赖的版本,也正是因为继承了这个依赖,所以我们在写依赖时才不需要写版本号。

4、 执行打包操作的配置。

5、 自动化的资源过滤。

6、 自动化的插件配置。

7、 针对 application、properties 和 application、yml 的资源过滤,包括通过 profile 定义的不同环境的配置文件,例如 application-dev、properties 和 application-dev、yml。

总结就是打包用的

SpringBoot与SpringCloud 区别

SpringBoot是快速开发的Spring框架,SpringCloud是完整的微服务框架,SpringCloud依赖于SpringBoot。

spring boot监听器流程?

1、 通过app.addListeners注册进入
2、初始化一个SpringApplicationRunListeners进行处理

3、 从spring.factories中读取监听器处理类EventPublishingRunListener

4、 通过createSpringFactoriesInstances创建监听器处理类实例

5、 调用监听器listeners.starting()的方法来启动。

6、 底层把事件处理交给线程池去处理

28、SpringBoot 支持哪些日志框架?推荐和默认的日志框架是哪个?

SpringBoot 支持 Java Util Logging, Log4j2, Lockback 作为日志框架,如果你使用 Starters 启动器,SpringBoot 将使用 Logback 作为默认日志框架

SpringBoot 中如何解决跨域问题 ?

什么是跨域问题

当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域;

当前页面url 被请求页面url 是否跨域 原因
http://www.test.com/ http://www.test.com/index.html 否 同源(协议、域名、端口号相同)
http://www.test.com/ https://www.test.com/index.html 跨域 协议不同(http / https)
http://www.test.com/ http://www.baidu.com/ 跨域 主域名不同(test / baidu)
http://www.test.com/ http://blog.test.com/ 跨域 子域名不同(www / blog)
http://www.test.com:8080/ http://www.test.com:7001/ 跨域 端口号不同(8080 / 7001)

为什么会出现跨域问题?

同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。正是出于浏览器的同源策略限制,才会有跨域问题;
所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),域名,主机(host)和端口号(port);同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互
所以,用最简单的话来说,就是前端可以发请求给服务器,服务器也可以进行响应,只是因为浏览器会对请求头进行判断,所以要么前端设置请求头,要么后端设置请求头;

跨域问题报错

错误中包含了Access-Controll-Allow-Origin这样字样的错误

  1. Access to XMLHttpRequest at 'http://localhost:8080/t1' from origin 'http://localhost:63342' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
  2. test1.html?_ijt=aekdfma33ut4n31cgsohdrjt89:17 {readyState: 0, getResponseHeader: ƒ, getAllResponseHeaders: ƒ, setRequestHeader: ƒ, overrideMimeType: ƒ, …}
  3. jquery-1.9.1.min.js:5 GET http://localhost:8080/t1 net::ERR_FAILED 200

错误中包含了Access-Controll-Allow-Origin这样字样的错误
image.png

如何在springboot中解决跨域问题

https://blog.csdn.net/likun557/article/details/122572011
对于 CORS的跨域请求,主要有以下几种方式可供选择:

  1. 返回新的CorsFilter
  2. 重写 WebMvcConfigurer
  3. 使用注解 @CrossOrigin
  4. 手动设置响应头 (HttpServletResponse)
  5. 自定web filter 实现跨域

跨域可以在前端通过 JSONP 来解决,但是 JSONP 只可以发送 GET 请求,无法发送其他类型的请求,在 RESTful 风格的应用中,就显得非常鸡肋;
因此我们推荐在后端通过 (CORS,Cross-origin resource sharing) 来解决跨域问题。这种解决方案并非 SpringBoot 特有的,在传统的 SSM 框架中,就可以通过 CORS 来解决跨域问题,只不过之前我们是在 XML 文件中配置 CORS ,现在可以通过实现WebMvcConfigurer接口然后重写addCorsMappings方法解决跨域问题,这也是解决方法之一。
CORS分为局部配置与全局配置,如果使用了局部跨域是会覆盖全局跨域的规则,所以可以通过 @CrossOrigin 注解来进行细粒度更高的跨域资源控制;其实无论哪种方案,最终目的都是修改响应头,向响应头中添加浏览器所要求的数据,进而实现跨域;

  1. @Configuration
  2. public class corsFilter {
  3. @Bean
  4. public CorsFilter CorsFilter() {
  5. CorsConfiguration corsConfiguration = new CorsConfiguration();
  6. corsConfiguration.addAllowedOriginPattern("*");
  7. corsConfiguration.addAllowedHeader("*");
  8. corsConfiguration.addAllowedMethod("*");
  9. corsConfiguration.setAllowCredentials(true);
  10. UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
  11. urlBasedCorsConfigurationSource.registerCorsConfiguration("/**",corsConfiguration);
  12. return new CorsFilter(urlBasedCorsConfigurationSource);
  13. }
  14. }

2、实现WebMvcConfigurer里面的addCorsMappings方法

~~~java @Configuration public class corsFilter1 implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(“/*”) // 匹配所有的路径 .allowCredentials(true) // 设置允许凭证 .allowedHeaders(““) // 设置请求头 .allowedMethods(“GET”,”POST”,”PUT”,”DELETE”) // 设置允许的方式 .allowedOriginPatterns(“*”); } }

  1. ## 3、@CrossOrigin局部跨域通过
  2. ```Java
  3. @GetMapping("/t2")
  4. @CrossOrigin
  5. public Map t2() {
  6. HashMap<String, Object> map = new HashMap<>();
  7. User user = new User();
  8. user.setUsername("123456");
  9. user.setPassword("程世玉");
  10. map.put("user",user);
  11. return map;
  12. }

也可以指定允许通过的ip

  1. /**
  2. * 如果只是想部分接口跨域,且不想使用配置来管理的话,可以使用这种方式
  3. * 添加响应头解决跨域
  4. * @return
  5. */
  6. @RequestMapping(value = "/user_2", method = RequestMethod.POST)
  7. @CrossOrigin(origins = "http://172.16.71.27:8080", maxAge = 3600)
  8. public User getUser_2(@RequestParam Long id) {
  9. return new User(id, "Booker", "admin", "sdfsdkjf93hu8dvn");
  10. }

4、添加响应头解决跨域

  1. @RequestMapping(value = "/user-1")
  2. public User getUser_1(HttpServletResponse response ) {
  3. // 允许所有,不安全
  4. response.addHeader("Access-Control-Allow-Origin", "*");
  5. response.addHeader("Access-Control-Max-Age", "10");
  6. response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  7. response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT");
  8. response.setHeader("Access-Control-Allow-Credentials", "true");
  9. return new User(1L, "Booker", "admin", "sdfsdkjf93hu8dvn");
  10. }

5、ajax跨域访问增加响应头

  1. $.ajax({
  2. url: "http://xxxx.xxxx.com/api/user/user-1",
  3. type: "post",
  4. dataType: "text",
  5. contentType: "application/json",
  6. data: JSON.stringify(data),
  7. headers: {'Content-Type': 'application/json'},
  8. success: function (res) {
  9. alert(res);
  10. }
  11. })

6、手写反向代理解决跨域问题

~~~java @SpringBootApplication public class SpringBoot1DayApplication {

public static void main(String[] args) {
    SpringApplication.run(SpringBoot1DayApplication.class, args);
}


@Resource
private RestTemplateBuilder restTemplateBuilder;

@Bean
public RestTemplate restTemplate() {
    return restTemplateBuilder.build();
}

}






> 代理类:通过restTemplate,模拟发请求,等于说我们只要暴露这一个接口就可以,其余接口统统可以通过这个接口进行访问!!!
>
> 核心方法:
>
>~~~java
> @RequestMapping("/api/**")
> @CrossOrigin
> public Object t3(HttpServletRequest request) {
>  String url = "http://localhost:8080";
>  return restTemplate.getForObject( proxyAddress+ request.getRequestURI().replace("/api", ""), Object.class);
> }
>

全部代码

~~~java package com.example.springboot1_day.Handler;

import com.example.springboot1_day.eneity.User; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map;

/**

  • @author 程世玉
  • @create 2022/3/23 21:32
  • @PROJECT_NAME SpringBoot-Homology
  • @Description */ @RestController public class UserHandler {

    @Value(“${proxy.address}”) private String proxyAddress;

    @Resource private RestTemplate restTemplate;

@GetMapping("/t1")
public Map t1() {
    HashMap<String, Object> map = new HashMap<>();
    User user = new User();
    user.setUsername("123456");
    user.setPassword("程世玉");
    map.put("user",user);

    return map;
}


@GetMapping("/t2")
public Map t2() {
    HashMap<String, Object> map = new HashMap<>();
    User user = new User();
    user.setUsername("123456");
    user.setPassword("程世玉");
    map.put("user",user);

    return map;
}


@RequestMapping("/api/**")
@CrossOrigin
public Object t3(HttpServletRequest request) {
    String url = "http://localhost:8080";
    return restTemplate.getForObject( proxyAddress+ request.getRequestURI().replace("/api", ""), Object.class);
}

}






> 所有解决跨域问题,不外乎就是解决浏览器拦截问题,要么前端设置请求头,要么后端设置请求头,无论谁设置请求头,浏览器只要放行即可


# 五、SpringBoot中RestTemplate
> spring框架提供的RestTemplate类可用于在应用中调用rest服务,它简化了与http服务的通信方式,统一了RESTful的标准,封装了http链接, 我们只需要传入url及返回值类型即可。相较于之前常用的HttpClient,RestTemplate是一种更优雅的调用RESTful服务的方式。



> 在日常项目开发中,有时候我们需要调用第三方接口数据,常用的方法有传统JDK自带的URLConnection,Apache Jakarta Common下的子项目HttpClient ,Spring的RestTemplate。



> 这么一解释,就明白了RestTemplate是什么了,就是一个类似于HttpClient一样的框架,封装了一些get请求,post请求,put请求等等请求的方法,用来模拟请求,让我们可以通过Java程序想其他不同端口的服务接口访问数据。

## 1、RestTemplate API使用

### postForEntity()(有请求体)



```java
//设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
headers.add("key1","value1");
headers.add("key2","value2");

HttpEntity<User> entity = new HttpEntity<>(new User(), headers);

String url = "http://xxx.com";
//发送post请求
ResponseEntity<R> responseEntity = restTemplate.postForEntity(url, entity, R.class);
R r = responseEntity.getBody();
if (HttpStatus.OK.value() != r.getStatus()) {
    log.error("发送错误:{}", r.getMsg());
}

postForEntity()(有请求参数)

String url="http://xxx.com??p1={1}&p2={2}";

ResponseEntity<Map> responseEntity = restTemplate.postForEntity(
                url,
                null,
                Map.class,
                "aa","bb");


postForObject()

//参数是Book类型,返回值也是Book类型
Book book = restTemplate.postForObject("http://127.0.0.1:8080/updatebook", book, Book.class);

post方法获取List数据

~~~java List voList = Lists.newArrayList();

HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON_UTF8); headers.add(“key1”,”value1”); headers.add(“key2”,”value2”);

HttpEntity entity = new HttpEntity<>(“”, headers); ProductTypeVO[] responseEntity = restTemplate.postForObject( url, entity, ProductTypeVO[].class);

if (null != responseEntity) { voList = Arrays.asList(responseEntity); }

```

Spring Boot 中的监视器是什么?(什么是Spring Boot Actuator)?

Spring boot actuator 是 spring 启动框架中的重要功能之一,Spring boot 监视器可以访问生产环境中正在运行的应用程序的当前状态。监视器模块公开了一组可直接作为 HTTP URL 访问的 REST 端点来检查状态。

什么是 CSRF 攻击?

CSRF 代表跨站请求伪造,这是一种攻击,迫使最终用户在当前通过身份验证的Web 应用程序上执行不需要的操作。CSRF 攻击专门针对状态改变请求,而不是数据窃取,因为攻击者无法查看对伪造请求的响应。

如何使用 Spring Boot 实现异常处理?

Spring 通过使用 @ControllerAdvice 注解处理异常,实现一个ControllerAdvice 类来处理控制器类抛出的所有异常。

如何监视所有 Spring Boot 微服务?

Spring Boot 提供监视器端点监控各个微服务,这些端点对于获取有关应用程序的信息(如它们是否已启动)以及它们的组件(如数据库等)是否正常运行很有帮助。但是用监视器的一个主要缺点是,必须单独打开应用程序的知识点以了解其状态或健康状况。

图灵SpringBoot

1、Spring MVC整合Tomcat底层原理分析

理论前提分析

springmvc整合tomcat时要配置一个tomcat的web.xml文件,tomcat在启动的时候就会去加载这个文件,里面配置了一个DispatcherServlet;
image.png
像上面的这个servlet配置,当前端发起的请求带上前缀app时,都交由该servlet来处理;而且我们的项目之所以能够接收到前端的请求都是因为我们这里配置的这个DispatcherServlet;
我们都知道tomcat是一个容器,里面装的都是些Servlet;Spring 也有一个IOC容器,只不过这个容器装的是Bean组件对象;
浏览器发起请求时,请求首先会被tomcat接收到,然后tomcat就将相应的请求交给相应的DispatcherServlet来处理(比如说访问上面配置的servlet需要带上app这个前缀,由该DispatcherServlet处理);
这个时候还有一个问题,就是DispatcherServlet是如何将接收到的请求匹配到每一个精确的请求方法的映射路径的?首先我们的映射路径是写在一个个controller控制器的请求方法中上的,而且这controller也是Spring容器中的一个bean对象;
所以这个DispatcherServlet就会去Spring容器中找到相应的controller对应的bean对象,然后遍历这个controller中的请求方法看看哪个符合要求; 这不就意味着这个DispatcherServlet内部就得需要一个Spring容器对象,而且是在web.xml文件中每配置一个DispatcherServlet都会对应一个spring容器;这就意味着我们可以在web.xml文件中配置多个DispatcherServlet,对应多个Spring容器,多个spring配置文件以及每个DispatcherServlet都有自己的请求映射路径;
比如说,我们再次在web,xml文件中配置一个映射路径为/app1/*的DispatcherServlet;那么当我们在浏览器中发起不同的请求时,将由不同的DispatcherServlet处理,转发到各种对应的spring配置文件中注册的控制器中;
image.png
这也更进一步印证了每一个DispatcherServlet都会有对应一个属于自己的spring容器;关于这个spring容器我们可以在DispatcherServlet的超级父类FrameworkServlet中找到这个容器属性;
image.png
image.png

SpringMvc整合tomcat时,tomcat是外嵌的,它的创建流程我们先不关心,但是spring容器的什么时候创建的呢?
https://www.bilibili.com/video/BV1JX4y1P71J?p=2&t=399.9

一般我们在进行SSM整合的时候,会有一个springmvc的配置文件专门扫描系统中的Controller控制器以及一个spring的配置文件来扫描javabean、service层以及dao层的bean;
为什么要这样呢?直接在配置SpringMvc的配置文件时将Controller控制器以及javabean、service层以及dao层的bean都扫描进容器中不就行了吗?
这是因为前面我们说到,一个tomcat容器中可以配置多个DispatcherServlet对应多个SpringMvc的配置文件,自然也就对应多个SpringMvc容器;如果我们直接在SpringMvc的配置文件的配置文件中扫描了系统中所有的bean对象,这就意味着每一个DispatcherServlet对应的容器都要单独扫描了系统中所有的bean对象,这是因为每一个DispatcherServlet对应的springmvc容器都是独立的;这也造成了一个系统中所有的bean对象在每一个mvc容器内部中都创建了一份;
一个系统中所有的bean对象在每一个mvc容器内部中都创建了一份,那么这些就都是多例的对象,当我们需要在同一个系统中使用单例对象时就无法得到满足,所以才需要有一个springmvc的配置文件专门扫描系统中的Controller控制器以及一个spring的配置文件来扫描javabean、service层以及dao层的bean;这样spring的配置文件扫描的javabean、service层以及dao层的bean能够是单例的,因为只有一个spring容器,而springmvc容器就能有多个;
image.png
这也是Spring中父子容器的处理问题;这个Spring容器对应的配置文件可以在web,xml文件中利用一个监听器进行配置,如下图
image.png

DispatcherServlet底层工作原理分析

Spring MVC零配置底层原理分析(注解开发)

其实就是将web.xml文件用配置类替换掉而已;
image.png
修改代码,设置父容器
image.png

https://www.yuque.com/matteo-irbtp/xniix0/sdq038/edit#KVbjT
可以看出,SpringMvc是依靠tomcat的;

4、Spring Boot整合Tomcat底层原理分析

SpringMvc+tomcat 跟SpringBoot+tomcat 有很大的不同,首先启动顺序就不一样了;
SpringMvc+tomcat 是先启动tomcat,然后再加载SpringMvc相关的功能,而且SpringMvc极大的程度依靠tomcat的servlet规范;
而SpringBoot+tomcat 的启动顺序是先启动Spring/ SpringBoot ,然后在其内部启动tomcat;

SpringBoot在启动的时候是如何启动tomcat以及如何将将DispatcherServlet放入tomcat中的,这两个问题解决了,那么SpringBoot内置tomcat的原理也就弄清除了;

image.pngimage.png
image.png
image.png
image.png
image.png
image.png
修改image.png
image.png
image.png

目前这样写代码有什么问题?

5、Spring Boot中Tomcat启动原理分析

6、Spring Boot零配置底层原理分析