Spring框架 - SpringBoot

前言

25题。

项目中为什么选择SpringBoot?

SpringBoot简化了Spring,开发效率更高。

它的主要优点如下:

  1. 版本锁定:在父工程中进行了大量常见依赖的版本锁定,我们就不用去找了;

  2. 起步依赖 :将依赖进行组装,并且允许程序员以starter的方式进行引入;

  3. 默认配置:实现了大量依赖框架的默认配置项,不需要自己配置;

  4. 内置 Tomcat

缺点:SpringBoot可能会装载大量用不到的对象,会浪费资源空间。

SpringBoot的核心注解是哪个?

SpringBoot的核心注解是@SpringBootApplication(自动装配),将其标记在启动类上,表示这是一个SpringBoot应用。

该注解主要包含了以下3个注解:

  1. @SpringBootConfiguration:实现配置文件的功能;
  2. @EnableAutoConfiguration:打开或关闭某个自动配置;
  3. @ComponentScan:默认扫描启动类所在的包。

SpringBoot中的starter是干什么的?

每个starter都可以为我们提供某个服务场景所需要的一系列依赖。在导入starter之后,SpringBoot主要帮我们完成了两件事情:

  1. 相关组件的自动导入;

  2. 相关组件的自动配置。

SpringBoot可以有哪些方式加载配置?

常见的有三种:

  1. 配置文件 :比如propertiesyamlyml(常用);

  2. 系统环境变量:但不推荐;

  3. 命令行参数:一般用于临时修改配置。

bootstrap.yml和application.yml有何区别?

都是SpringBoot支持的核心配置文件,区别在于:

  1. boostrapapplicaton优先加载,在应用程序上下文的引导阶段生效,且里面的属性不能被覆盖。一般来说我们在SpringCloud Config中会用到它(Nacos),一般用于多环境配置;

  2. application用于SpringBoot项目的自动化配置,一般来说我们会将自己项目的业务配置项写在这里面。

SpringBoot读取配置的方式有几种?

常见的有两种:

  1. 使用@Value配合EL表达式(@Value("${name}")) 直接注入对应的值;

  2. 使用@ConfigurationProperties(prefix=" ")把对应的值绑定到一个配置对象,然后将配置对象注入到需要的地方。

推荐使用使用第二种方式,在配置比较多的情况下,操作简单,可读性好。

SpringBoot项目如何热部署?

使用Spring Boot的开发工具(DevTools)模块实现。当开发人员更改文件后,该模块就会自动部署修改到服务器并自动重启服务器。

SpringBoot项目如何实现方法的异步调用?

异步调用指的是两个方法aba调用b的时候,不用等b执行完毕就可以继续向下执行,一般用在a方法不需要使用b方法返回结果的场景,可提高运行效率。

SpringBoot只需要做两个操作就可以实现异步调用:

  1. 在启动类上添加@EnableAsync注解,开启异步调用支持;

  2. 在被调用的方法上添加@Async注解。

SpringBoot中如何实现定时任务?

主要有两种方式:

  1. 使用第三方框架Quartz

  2. 使用SpringTask:主要是通过@Scheduled注解来实现定时任务触发。

@Scheduled注解主要属性如下:

  • fixedRate:按一定的频率执行任务,参数类型为long,单位ms
  • fixedDelay:上一次任务执行完后多久再执行,参数类型为long,单位ms
  • initialDelay:延迟多久再第一次执行任务,参数类型为long,单位ms
  • cron:使用cron表达式指定任务在特定时间执行。

集群部署用xxl-job来实现定时任务。涉及到集群部署,SpringTask定时任务不支持,会造成同一个任务重复执行多份,Redis分布式锁需要手动修改比较麻烦。xxl-job可以在后台随时调整时间规则,统一管理所有定时任务。

cron表达式?

cron表达式其实就是一个字符串,通过cron表达式可以定义任务的触发时间。SpringTask支持的cron表达式分为6个域,由空格分隔开,每个域代表一个含义:秒 分 时 日 月 周。每个域都支持精准数值的写法,也支持一些具有特殊意义的字符,主要的有:

(1) *:表示任意

(2) ?:表示忽略,只能用在日和周两个域

(3) -:表示区间,

(4) /:表示起始时间开始触发,然后每隔固定时间触发一次

(5) ,:表示列出枚举值,例如在分域使用5,20则意味着在520分触发一次

(6) #: 用于确定每个月第几个星期几

SpringBoot中如何解决跨域问题?

跨域问题指的是,前后端出现域名、端口、协议任意一个不同,都属于跨域。

解决方法 :添加一个配置类,实现WebMvcConfigurer接口,然后重写addCorsMappings方法即可,最后都是可以采用跨域资源共享CORS来解决跨域问题。

如何理解拦截器?

拦截器是Spring提供的一种拦截机制,实现对指定请求路径进行拦截:

  1. 单体项目中拦截器校验token,拦截用户信息存入ThreadLocal

  2. 微服务在网关校验,获取用户ID放到请求头中传入后面微服务,微服务中拦截器拦截请求获取用户信息,将其放入ThreadLocal中。

自定义一个拦截器,需要实现HandlerInterceptor接口,并重写3个方法:

  1. preHandle: 这个方法在Controller处理请求之前被调用,通过方法的返回值可以确定是否放行请求;
  2. postHandle:这个方法在Controller处理请求之后被调用;
  3. afterCompletion:在整个请求结束之后被调用,此方法主要用于进行资源清理。

拦截器和过滤器的区别是什么?

都可以实现请求的拦截处理,不同点有4个:

  1. 技术栈所属 不同:过滤器属于JavaWeb技术,依赖Servlet容器;而拦截器是属于Spring的技术;

  2. 实现原理 不同:拦截器是基于Java的反射机制,而过滤器是基于函数回调;

  3. 拦截范围 不同:过滤器可以拦截所有请求,而拦截器主要是针对发往controller请求;

  4. 拦截位置不同:过滤器在前端控制器前拦截,而拦截器在前端控制器后拦截。

SpringBoot中properties文件如何配置文件上传上限?

ini 复制代码
# 设置单个文件上传大小限制为10MB

spring.servlet.multipart.max-file-size=10MB

# 设置总上传文件大小限制为20MB

spring.servlet.multipart.max-request-size=20MB

SpringBoot如何实现缓存?

SpringCacheSpring提供的一个缓存框架,它可以通过简单的注解实现缓存的操作,常用的注解有下面几个:

  • @EnableCaching: 开启基于注解的缓存;

  • @CachePut: 一般用在查询方法上,表示将方法的返回值放到缓存中;

  • @Cacheable: 一般用在查询方法上,表示在方法执行前先查看缓存中是否有数据,如果有直接返回;如果没有,再调用方法体查询数据并将返回结果放到缓存中;他有两个关键属性:

    • value: 缓存的名称,每个缓存名称下面可以有多个key
    • key: 缓存的key,支持Spring的表达式语言SPEL语法
  • @CacheEvict: 一般用在增删改方法上 ,用于清理指定缓存,可以根据key清理,也可以清理整个value下的缓存。

SpringCache还有一个优点:就是可以随意切换底层的缓存软件,比如:Redis、内存等等。

项目中是如何进行异常处理的?

项目中是使用全局异常处理器来实现异常处理的,核心是两个注解:

  1. @RestControllerAdvice:标注在类上,声明该类是处理异常的类;
  2. @ExceptionHandler:标注在方法上,声明该方法是处理什么异常。

在全局异常处理器中一般定义三种异常:

  1. 指定异常 :指定异常指的是用户操作产生的与程序设计相关的异常,比如字段重复异常、Validation校验异常等等,这类异常捕获之后,我们会根据异常的消息提示,给前端一个确定的返回结果;

  2. 业务异常:业务异常是由于用户不正当操作产生的与业务相关的的异常,这种异常往往需要我们自定义,指定异常提示信息,然后在程序的相关位置手动抛出。然后异常处理器捕获之后,直接将异常提示消息返回给前端;

  3. 异常时兜底异常:此处主要捕获的是不属于上面两种异常的异常,一般是一些程序员代码不够严谨引发的运行时异常,对于这些异常,我们处理方案是首先要把错误记录到日志系统中,然后给前端一个类似于服务器开小差了之类的统一提示。

项目中是如何存储文件的?

主要有三类存储方式:

  1. 第一种是直接将文件保存到服务到硬盘,这种方式操作方便,但是扩容困难,而且安全保障不高,现在基本不再使用;

  2. 分布式文件存储系统:如果文件是隐私性比较高,建议使用自己搭建的分布式文件存储系统,安全性也比较高;

  3. 第三方服务:如果文件隐私性不高,可以考虑使用第三方服务,比如阿里云或者七牛云。

项目中是如何进行参数校验的?

项目中的参数校验是使用validation来实现的,它有一些特定的注解,这些注解主要标注在请求参数或者是参数对象对应类的属性上,每个注解都有自己的校验规则。

如果我们输入的请求参数不符合对应的校验规则,系统就会抛出异常,此时我们只需要在全局异常处理器中捕获异常,然后给前端提示即可。

常用的注解有下面这些:

  • @Null:可以标注在任意类型元素上,被标注的元素必须为null

  • @NotEmpty:可以标注在字符串,集合,数组,map上,被标注的元素必须不能为null,也不能是空串

  • @Range:标注在数值类型上,数值的大小必须在指定的范围内,对于null无效

  • @Digits(integer(数值的位数) =3 , fraction(小数的位数)=2),被注释的元素必须是一个数字,其值必须在可接受的范围内

  • @size(min=,max=):可标注在字符串,数组,集合,map用于控制长度

  • @Email:邮箱

  • @URL:合法的地址

如何理解分组校验?

比如我们在新增和修改一个用户对象时,都会接收User对象作为请求参数,但是新增要求对象的id为空,而修改则要求id字段不能为空。这个时候就需要使用到分组校验。分组校验其实就是定义多套校验规则,对于指定的功能,我们按照要求指定它使用哪套规则即可。

SpringBoot自动装配的过程是可以被干预的吗?

可以的。在实践之中,如果我想要排除一个自动装配类,就会利用@SpringBootApplication注解的exclude属性,比如:exclude={DataSourceAutoConfiguration.class},即可。

或者在yml配置文件中使用spring.autoconfigure.exclude=DataSourceAutoConfiguration.class来排除自动配置。

比如SpringBoot内置tomcat,现在我想使用netty,怎么办?

SpringBoot内置tomcat作为web服务器,如果想要更换为netty,需要如下步骤:

  • 更换依赖,在pom.xml中引入netty,然后在spring-boot-starter-web依赖除移除tomcat
  • 如果有需要的话,可以创建一个配置类修改netty配置,然后启动应用即可

@Controller和@Service交换会发生什么?

完整问题:现有控制层类StudentController和业务层类StudentService,将这两个类的@Controller注解和@Service注解进行交换,应用程序还能正常启动吗,StudentController类还可以处理请求吗?

可以正常启动。因为@Controller注解和@Service注解都继承了@Component注解,在Spring容器眼里都是一样的,只是方便程序员区分。真正决定能否匹配url、处理请求的是@RequestMapping等注解。

SpringBoot中都有哪些场景会导致事务失效?

我知道的有6种场景:

  1. 事务方法不是public修饰的 ,因为Transaction注解基于SpringAOP的动态代理,而SpringAOP的动态代理只适用于public方法
  2. 当前类没有交给IOC容器管理
  3. 抛出异常类型不是运行时异常
  4. 方法执行失败时,抛出的异常被捕获,导致事务没有发现异常无法回滚
  5. 同一个类中有事务方法也有非事务方法,非事务方法调用事务方法,因为非事务方法没有@transaction注解,相当于直接调用普通方法
  6. 事务传播行为使用有误 :如一个事务方法A内部调用另一个事务方法BA的传播机制是默认的,B是必须新事务。进入A时,A使用默认事务,调用B时,B又创建了一个新事务,AB不是一个事务了。当A抛出异常时,A就会回滚,因为BA不是一个事务,就不会回滚。

如何自定义一个注解?

比如:

Java 复制代码
public @interface MyAnnotation {
    public String name();
    int age();
    String sex() default "女";
}
  • 访问修饰符必须为public,不写默认为public
  • 该元素的类型只能是基本数据类型、StringClass、枚举类型、注解类型以及一维数组;
  • 该元素的名称一般定义为名词,如果注解中只有一个元素,名字起为value最好;
  • ()不是定义方法参数的地方,也不能在括号中定义任何参数,仅仅只是一个特殊的语法;
  • default代表默认值,值必须定义的类型一致;
  • 如果没有默认值,代表后续使用注解时必须给该类型元素赋值。

什么是元注解?

配置注解需使用元注解,元注解是专门修饰注解的注解,常见的有@Target@Retention@Documented@Inherited

@Target

@Target是专门用来限定某个自定义注解能够被应用在哪些Java元素上面的,包含一个ElementType[] valueElementType常见的有:

  1. TYPE:类、接口、枚举等
  2. METHOD:方法
  3. CONSTRUCTOR:构造方法

@Retention

@Retention注解,用来修饰自定义注解的生命力。

  1. 如果一个注解被定义为RetentionPolicy.SOURCE,则它将被限定在Java源文件中,那么这个注解既不会参与编译也不会在运行期起任何作用,这个注解就和一个注释是一样的效果,只能被阅读Java文件的人看到;
  2. 如果一个注解被定义为RetentionPolicy.CLASS,则它将被编译到Class文件中,那么编译器可以在编译时根据注解做一些处理动作,但是运行时JVMJava虚拟机)会忽略它,我们在运行期也不能读取到,是默认的;
  3. 如果一个注解被定义为RetentionPolicy.RUNTIME,那么这个注解可以在运行期的加载阶段被加载到Class对象中。那么在程序运行阶段,我们可以通过反射得到这个注解,并通过判断是否有这个注解或这个注解中属性的值,从而执行不同的程序代码段。我们实际开发 中的自定义注解几乎都是使用的RetentionPolicy.RUNTIME

@Documented

@Documented注解,是被用来指定自定义注解是否能随着被定义的java文件生成到JavaDoc文档当中

@Inherited

@Inherited注解,是指定某个自定义注解如果写在了父类的声明部分,那么子类(继承关系)的声明部分也能自动拥有该注解。该注解只对@Target被定义为ElementType.TYPE的自定义注解起作用。

SpringBoot常用的starter?

  1. spring-boot-starter-web:用于构建web应用
  2. spring-boot-starter-test:用于测试
  3. spring-boot-starter-data-redisredis相关
  4. spring-boot-starter-validation:数据验证
相关推荐
lang201509283 小时前
Spring Boot优雅关闭全解析
java·spring boot·后端
刘一说4 小时前
Spring Boot 启动慢?启动过程深度解析与优化策略
java·spring boot·后端
lang201509286 小时前
Spring Boot缓存机制全解析
spring boot·后端·缓存
摇滚侠6 小时前
Spring Boot 3零基础教程,WEB 开发 默认页签图标 Favicon 笔记29
java·spring boot·笔记
Jeled6 小时前
AI: 生成Android自我学习路线规划与实战
android·学习·面试·kotlin
lang201509286 小时前
Spring Boot SQL数据库全攻略
数据库·spring boot·sql
我是华为OD~HR~栗栗呀7 小时前
华为od-22届考研-测试面经
java·c++·python·功能测试·华为od·华为·面试
是梦终空7 小时前
计算机毕业设计241—基于Java+Springboot+vue的爱心公益服务系统(源代码+数据库+11000字文档)
java·spring boot·vue·毕业设计·课程设计·毕业论文·爱心公益系统
Python算法实战9 小时前
腾讯送命题:手写多头注意力机制。。。
人工智能·算法·面试·大模型·强化学习
讨厌吃蛋黄酥9 小时前
🔥 JavaScript异步之谜:单线程如何实现“同时”做多件事?99%的人都理解错了!
前端·javascript·面试