【面试题-8】Spring/Spring MVC/Spring Boot/Spring Cloud

(1)Spring 中应用了哪些设计模式?

使用了如下设计模式:

(1)工厂模式:Spring 的 IOC 容器是一个大工厂,所有 Bean 创建都在这个工厂里。

(2)代理模式:SpringAOP 的实现,就用了代理模式,实现对方法的增强。

(3)单例模式:Spring 中 Bean 对象的创建,默认是单例的。

(4)模板模式:Spring 中封装了一些框架工具,如 RedisTemplate,是模版模式的表现。

(5)观察者模式:用 Spring Context 发异步消息,内部维护了一个监听者集合,发布事件时通知所有监听者,这是观察者模式的体现。

(6)适配器模式:@RestControllerAdvice 注解,使用到了适配器模式。

(7)策略模式:Spring 中有一个 Resource 接口,它的不同实现类,会根据不同的策略去访问资源。

参看博客:如何使用Spring Context实现消息队列统一异常处理


(2)说下什么是 IOC ?什么是 DI ?

IOC 是一种容器思想,

假如没有 IOC,我们开发中需要频繁创建 Bean 对象,而这些 Bean 对象大多是可以复用的,

手动创建效率太低,耦合高,不利于扩展和维护。

而用了 IOC 容器,可将 Bean 的创建和管理交给 IOC 容器,

我们只需要关注 Bean 的依赖关系,需要时直接注入(DI),非常方便。


(3)说下 Spring Bean 生命周期?

实例化 => 属性赋值 => 初始化 => 使用 => 销毁


(4)Spring 中的单例 Bean 会有线程安全问题吗?

不会,虽然 Spring 中默认创建的 Bean 是单例,被所有线程所共享的,

但 Spring 中 Controller、Service、DAO 等,这些 Bean 大多是无状态的,

就是说不会存储数据,也就不存在线程安全问题。

如果需要保证安全的话,

(1)可以修改 Bean 的创建方式为非单例,这样每一个线程都会创建一个新的 Bean;

(2)或者将 Bean 保存到 ThreadLocal 中;


(5)说说循环依赖是什么?

循环依赖是自己依赖自己,或者与其他的 Bean 互相依赖,你的创建依赖于我,我的创建依赖于你。

因为 Spring 有三级缓存的存在,可以解决属性注入方式的循环依赖。


(6)Spring 是怎么解决循环依赖的?

是通过三级缓存的方式解决的,如 A、B 循环依赖,

(1)实例化 A,但由于 A 依赖 B,所以 A 实例化不完整,会先放在二级缓存中,暴露出来。

(2)实例化 B,发现 B 依赖 A,依次从一级缓存到三级缓存中找 A,结果会在二级缓存中找到 A,

(3)虽然 A 不太完善,但是存在,于是 B 实例化成功,放入到一级缓存中。

(4)最后实例化 A,A 依赖于 B,逐级查找,会在一级缓存中找到实例化完成后的 B,A 实例化完成,

(5)将 A 放入到一级缓存中,删除二级缓存中的A。

(6)A、B 的实例化就都完成。

需要注意,这种情况只接受属性注入的方式,如果 AB 均采用构造器注入或者 A 采用构造器,B 采用属性注入,都无法支持。


(7)如果是被 final 修饰的类要用哪种注入方式?

构造器注入


(8)说下 Spring 三级缓存?

Singleton Object Cache(一级缓存):存储已经创建完成的 Bean 单例对象;

Early Singleton Object Cache(二级缓存):存储早期创建的 Bean 单例对象

Singleton Factories Cache(三级缓存):存储用于创建单例 Bean 的 ObjectFactory。


(9)为什么要三级缓存?二级不行吗?

不行,因为要考虑到代理对象。

如果没有代理对象,二级缓存是可以的,但因为存在代理对象,如果只有二级缓存,在 Bean 初始化过程中,

生成的代理对象会覆盖掉二级缓存中的普通对象,可能会导致取到的 Bean 对象不一致。


(10)说说什么是 AOP ?

AOP 是面向切面编程,是使用动态代理实现的可对方法进行增强的技术。

有前置、返回、异常、最终和环绕通知。

参看博客:AOP技术


(11)你平时有用到 AOP 吗?怎么用的?

有用到,

(1)接口防抖,防止短时间内频繁调用接口;

(2)记录接口的访问信息,方便以后做统计;

(3)接口鉴权;

(4)参数校验,如 Valid 框架,自定义参数校验器;

用 AOP 需要注意两点,

(1)对于 AOP 中的异常不要进行捕获,否则增强方法的事务会失效;

(2)其次,对于 AOP 中的增强方法,最终通知要先于返回通知执行,这点在设计时需要注意。

参看博客:使用AOP处理参数使用AOP记录请求日志实现


(12)说说 JDK 动态代理和 CGLIB 代理 ?

(1)JDK 动态代理,是 Java 自带的代理机制,

通过实现 InvocationHandle 接口并使用 Proxy 类的 newProxyInstance 方法,

可在运行时动态生成代理类,要求被代理的类必须实现至少一个接口。


(2)CGLIB 代理,是基于字节码操作的代理机制,

通过继承被代理类,并覆写方法来实现代理功能。

CGLIB 动态代理可以代理没有实现接口的类,

它在运行时生成被代理类的子类,可以使用第三方库。


使用场景:

(1)CGLIB 动态代理创建的对象性能高,所花时间多,推荐用来创建单例对象,反之,使用 JDK 动态代理;

(2)JDK 动态代理要求被代理类至少实现一个接口,CGLIB 没有这个要求,所以也可以按照这个来选择。

(3)CGLIB 动态代理是通过继承来实现的,所以如果类是用 final 修饰的,那么就不能使用 CGLIB 动态代理

参看博客:【设计模式-3.4】结构型------代理模式


(13)说下 Spring 事务的传播机制?

事务的传播机制,是多个事务方法,互相调用时,事务的行为机制。

通过在 @Transational 注解中的 propagation 属性值设置,常用的值有:REQUIERD(默认)、SUPPORTS、REQUIRED_NEW。


假设目前有两个方法,方法 A 和方法 B,方法 A 中调用了方法 B。

默认情况下:如果 A 有事务,则调用的 B 加入到 A 的事务,两个方法有一个发生异常都发生回滚;

SUPPORTS:如果 A 有事务,则调用的 B 也按照事务执行,如果没有,则按非事务执行;

REQUIRED_NEW:无论 A 有没有加事务, B 都有事务,且 A 的异常不影响 B 的事务执行;

需要注意,这个事务的传播行为,是设置在被调用方的,即方法 B 上。

参看博客:SpringBoot项目的事务实现


(14)Spring 的声明式事务在哪些情况下会失效?

(1)手动捕获了异常;

(2)不在回滚异常内的异常,默认回滚异常是 Runtime Exception;

(3)非 public 修饰的方法上;

(4)事务传播没有设置好;

(5)在类里面调用本类成员方法,没有通过代理对象,事务会失效;

(6)没有交给 IOC 容器所管理的类;

(7)异步调用;

(8)数据库不支持事务;


(15)讲下 Spring MVC 的工作流程?

(1)用户发送的请求先到前置控制器(DispacherServlet);

(2)前置控制器访问处理映射器,查询对应的 handler,处理器映射器里存储了接口的请求类型,接口地址;

(3)处理映射器返回对应的处理器执行链;

(4)前置控制器请求处理适配器执行,在这里进行接口参数的封装;

(5)处理适配器,找对应的处理器(Controller) 执行;

(6)执行器执行完成后返回 ModeAndView 对象;

(7)处理器适配器将 ModeAndView 对象返回给前置控制器;

(8)前置控制器,请求视图解析器进行视图解析;

(9)视图解析器返回对应的 View 对象

(10)渲染 View 对象

(11)返回给前端

需要注意,

(1)不是所有请求都会走完整的流程,当 Controller 返回的不是 ModeAndView,而是 Json 时,前置控制器接收后,会直接返回前端。

(2)在请求处理器适配器执行前,中间会先执行拦截器,如果代码中有的话。


(16)SpringBoot 的自动配置原理了解吗?

在依赖(Jar 包)的静态资源目录(Resource 目录)的 META-INF 文件夹下有一个 spring.factories 文件,

该文件里是 Bean 清单,都是类的全限定类名。

在项目启动时,Spring Boot 会自动有选择性的创建这些 Bean 对象,放到 IOC 容器中。

之所以说有选择性,是配合了一些选择性装配的注解,如下:

@ConditionalOnProperty:有配置才装配;

@ConditionalOnClass:有字节码文件才装配;

@ConditionalOnBean:有 Bean 才装配;

@ConditionalOnJava:符合版本的 Java 才装配;

参看博客:Spring Boot中选择性加载Bean的几种方式


(17)Spring Cloud 中有哪些常用组件?它们的作用是什么?

Gateway:所有微服务的入口;

Nacos:注册中心、配置中心;

MQ:微服务之间的异步调用;

Dubbo/Feign:微服务之间的通信;

Sentinel/hystrix:微服务保护;


(18)讲下 Spring Boot 的启动流程呢?

(1)加载配置文件

(2)创建应用程序上下文

(3)自动装配 Bean

(4)扫描组件

(5)启动应用程序


(19)Feign 和 Dubbo 有什么区别和共同点?

【相同点】:都依赖注册中心。


【不同点】:

Dubbo: 支持多传输协议,默认 Dubbo 协议,长连接,适合高并发场景;

Feign: 基于 Http 传输协议,短连接,不适合高并发的访问;

参看博客:Feign技术Dubbo+Zookeeper使用


(20)网关和 Gateway 的区别?

网络层面上的网关是一种网络硬件设施或者软件,它的作用是连接不同类型、不同协议的网络,充当网络之间的桥梁。

常见的硬件网关有路由器,软件网关有代理服务器。

Gateway 是微服务架构的组件,是微服务请求的统一入口,可以实现请求转发、权限控制和限流。


(21)Nacos配置热更新的原理

Nacos Server 和 Nacos 客户端采用的是长轮询的方式,

服务端数据没有发生改变时,会持续连接,直到服务端的数据发生变化,或者连接超时的时候才会返回。


Nacos 配置热更新,存在一个比较服务端配置与客户端配置的过程,如果配置项过多,会导致比较的时间很长,配置同步效率变低。

对此,Nacos 采用了两点优化:

(1)分片,将配置按每 3000 个配置项分片,多次比较;

(2)分阶段比较更新,客户端把配置发给服务端,服务端将其中值有变化的配置 Key 返回给客户端,客户端拿到这些有变化的配置 Key,再循环逐个去获取服务端上新的 value,更新本地配置。也就是说配置的比较和修改后的配置值不是一次完成的。

参看博客:Nacos技术


(22)说下 Http 中的状态码呢?

http 状态码标识请求的状态,常见的状态码及含义如下:

2xx 成功:200(成功)、204(不含主体部分)、206(范围请求);

3xx 重定向:301(永久性重定向)、302(临时性重定向);

4xx 客户端错误:400(请求报文存在语法错误)、401(认证失败)、403(请求被拒绝)、404(没找到资源);

5xx 服务器错误:500(服务器错误)、503(服务不可用);

参看博客:HTTP状态码与首部字段

相关推荐
坐不住的爱码4 小时前
mybatis-动态sql语句-<foreach>
java·sql·mybatis
while(1){yan}4 小时前
HTTP的数据报格式
java·开发语言·网络·网络协议·http·青少年编程·面试
ID_180079054734 小时前
淘宝关键词搜索 API 系列 数据返回参考(附解析与实战)
java·服务器·前端
武子康4 小时前
大数据-186 Logstash JDBC vs Syslog Input:原理、场景对比与可复用配置(基于 Logstash 7.3.0)
大数据·后端·logstash
Seven975 小时前
剑指offer-51、构建乘积数组
java
宵时待雨5 小时前
C语言笔记归纳19:动态内存管理
java·开发语言·算法
沉浮yu大海5 小时前
基于SpringBoot3+Java17+Nacos的配置中心和本地配置文件加解密
java·spring cloud·nacos·java17
一勺菠萝丶5 小时前
Jenkins 中如何给角色分配多个不同名称的项目(Role 权限实战)
java·运维·jenkins
真上帝的左手5 小时前
15. 实时数据-SpringBoot集成WebSocket
spring boot·后端·websocket