2021年Java中高级面试必备知识点总结
在这个部分总结了2019年到目前为止Java常见面试问题,取其面试核心编写成这份文档笔记,从中分析面试官的心理,摸清面试官的“套路”,可以说搞定90%以上的Java中高级面试没一点难度。
本节总结的内容涵盖了:消息队列、Redis缓存、分库分表、读写分离、设计高并发系统、分布式系统、高可用系统、SpringCloud微服务架构等一系列互联网主流高级技术的知识点。
目录:
(上述只是一个整体目录大纲,每个点里面都有如下所示的详细内容,从面试问题——分析面试官心理——剖析面试题——完美解答的一个过程)
部分内容:
对于每一个做技术的来说,学习是不能停止的,小编把2019年到目前为止Java的核心知识提炼出来了,无论你现在是处于什么阶段,如你所见,这份文档的内容无论是对于你找面试工作还是提升技术广度深度都是完美的。
不想被后浪淘汰的话,赶紧搞起来吧,高清完整版一共是888页,需要的话可以点赞+关注
c(); // 不与 a b 共用一个
/*
情景1:
一旦出现了这个异常,a 方法就炸了,
因为 a、b 共用一个事务,所以它俩都会回滚
c 因为是一个新事务,所以不会回滚
*/
int i = 10 / 0;
}
// REQUIRED:单纯的需要一个事务,如果 a 已经有了,就会直接使用 a 的
@Transactional(propagation = Propagation.REQUIRED)
public void b(){
/*
情景2:
因为 a、b 共用一个事务,所以它俩都会回滚
c 不受影响
*/
int i = 10 / 0;
}
// REQUIRES_NEW:总是需要一个新的事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void c(){
}
1、同一个对象内,事务方法互调默认失效
上述的这个示例,如果 a、b、c 方法全都在同一个 service 下,那么 b、c 做的传播行为配置,都不会起作用,也就是说b、c都会跟 a 共用一个事务
除非b、c在其他不同的 service,那样才能使它们自己的配置生效
2、原因
事务是用代理对象来控制的,如果在 a 里面调用的是同一个 service 的 b、c方法,相当于把 b、c 的代码复制、粘贴过来了,也就是跳过了代理
3、解决
使用代理对象调用b、c方法,即可解决
-
导入 spring-boot-starter-aop 依赖,这个依赖引入了 aspectj
-
启动类开启 aspectj 动态代理功能,以后所有的动态代理都是 aspectj 创建的(即使没有接口也可以创建动态代理),对外暴露代理对象
@EnableAspectJAutoProxy(exposeProxy=true)
- 用代理对象对本类互调
AopContext.currentProxy()
调用方法
@Transactional(timeout = 30)
public void a(){
// 直接强转,然后b、c的传播行为设置就能起作用了
OrderServiceImpl orderService = (OrderServiceImpl) AopContext.currentProxy();
orderService.b();
orderService.c();
}
// REQUIRED:单纯的需要一个事务,如果 a 已经有了,就会直接使用 a 的
@Transactional(propagation = Propagation.REQUIRED)
public void b(){
}
// REQUIRES_NEW:总是需要一个新的事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void c(){
}
1、假失败
如果保存订单成功,远程锁库存假失败,那就会出现问题
假失败就是我们在订单服务调库存服务时, 库存锁定成功,然后由于服务器慢、卡顿、等故障原因,本地事务提交了之后,一直没返回到订单服务
此时再看订单服务,因为调用库存服务时间太长了,库存服务迟迟没有返回结果,可能就会触发 feign 的超时机制,在调用远程服务这里抛异常:read time out 读取超时,但是这个异常并不是我们手动抛的锁库存异常,而是 feign 的异常
并且订单服务,设计的回滚机制,是只要一出现异常就会全部回滚,
结果:库存锁定成功,订单服务因为 feign 的超时机制,出现异常,导致订单数据全部回滚,最终数据不一致
2、调用新服务出现异常之后,已经执行的服务不会回滚
假设库存锁定成功,将结果返回到了订单服务,我们根据结果又调用了积分服务,让它扣减积分,
结果积分服务内部出现异常,积分数据回滚
此时再看订单服务,订单服务感知到我们手动抛的积分异常,订单数据回滚,但是库存服务,却不会有任何感知,
结果:积分、订单数据全部回滚,库存给锁定了,也是数据不一致
只需要在订单服务的库存执行成功之后,添加一个 int i = 10 / 0;
,模拟积分服务出现异常,很容易就能复现这个问题
3、总结
本地事务,在分布式系统,只能控制住自己的回滚,控制不了其他服务的回滚
产生分布式事务的最大原因,就是网络问题 + 分布式机器
===============================================================
我们还是以我们之前的下单场景为例。比如我们来看这张图。这张图跟我们之前的下单场景稍微有些不一样,我们就以它为例,
我们现在有一个业务叫下单,就是我们的 business 这个业务,然后它首先要调用我们三个功能。第一个是我们扣库存,然后接下来是保存订单,订单保存完了我们可能还要扣减积分。
只有这三个功能同时调用成功了,我们这个单才算是下成功。
如果是我们以前的单体应用,我们将这三处代码全部写在一个系统里边。而且我们全部连想的是一个数据库。
那这样的话,我们使用本地事务就可以非常方便的控制住。只要有一个失败,大家全体回滚。
但是正是由于我们分布式系统的出现。
由于我们这个业务太大,我们不可能将所有业务全写进一个项目里边。所以我们拆分成了好多微服务。比如我们的库存服务,我们的订单服务。还有我们的用户账户服务,
我们现在拆分了三个服务,而且每个服务还是连自己的数据库操作自己的数据,还互相没有关系。
再加上分布式系统之间部署还可能不在一块。
比如我们这个库存服务在一号机器,订单在二号,账户在三号机器。
那这样我们想要完成整个下单逻辑,我们就要远程调用这三个机器的各个方法。
1、问题一
比如机器宕机,我们二号执行完了,想要调用我们三号业务。但是三号业务这个机器宕机了,那一宕机以后,会出现什么问题呢?
其实是二号,它不能感知到我们这个三号到底是执行成了还是败了。
如果是我们在二号调三号之前,它给炸了,那还好,我们二号知道它连不上三号,那把自己也回滚一下。
2、问题二
但是如果是我们二号调了三号机器的代码,有请求给它发过去了,然后三号机器代码可能都执行完了,正好在执行完的那一刻就要给它返回的时候,它给炸了。
那这样的话,二号机器就永远等不到它的返回,会认为它已经宕机了。
但是此时的二号机器,它是没办法知道我们三号机器到底是执行成了还是执行败了。
就算我们需要查三号机器成了还是败了,它都宕机了,也没法查了。
所以现在可能会由于机器宕机的问题,我们想要同步它们之间的状态不好同步。
因为我们想要让一个失败,大家全体失败,来做一个事务。
3、问题三
或者由于网络异常
,比如三号机器一切都执行成功了。然后把所有的成功消息都返回给订单服务了
结果我们消息刚发出去,老鼠把网线咬断了。那我们这个消息传不出去了,怎么办?
所以现在我们这个二号还是不知道我们这个三号机器它到底执行的状态怎么样。
那它们三个就无法同步我们的事务状态,
再加上我们分布式系统里边如果引入了更多中间件,一些消息中间件。造成的丢失乱序,包括一些数据的发送错误,我们经常类型转换转成了这个空指针异常的类型转不过来的。
但实际人家远程。执行成功了,只是你业务代码出了问题,
还有我们一些不可靠的这些网络 tCP 连接等等。
只要是我们这些网络的问题、机器服务节点故障的问题都会导致我们某一个机器的状态,它的这个成功失败,别的机器可能没办法感知。
那这样想要在分布式系统里边做事务,想协调一号、二号、三号机器,它们整体要么都回滚,要么都成功,这就非常难。
这就是我们的分布式事务。
只要我们有微服务,我们的业务太大,我们拆成微服务部署在了不同机器。
那我们在后来的业务开发中,我们一定百分百避免不了我们的分布式事务。
这个东西就是躲得过初一,躲不过十五。我们可以提前设计一些,比如我们前几个业务,我们通过自己的设计,我们把数据库揉在一起或者怎么着,我们终于躲过了分布式事务,但在后边一些复杂的业务又出现远程调用。我们总是躲不过。
我们不可能将所有的代码全部放在一个项目里边。因为现在的项目的规模都太大了,没有任何机器能负担住一个大型项目的运行。
所以只要是微服务架构,分布式事务就是无法避免的
分布式事务出现的原因就是我们节点之间互相的状态不能同步,包括网络状况问题。
我们这些数据互相感知不到,现在我们就希望有人能协调这个事情。
当然我们做这个之前我们先来考虑一下我们分布式系统里边的一些定理。
它既然能叫定理,就是我们不能打破的一个理论。
那我们在分布式系统里边有一个叫 CAP 原则,也叫 CAP 定理
。
================================================================
CAP 指的是一致性
、可用性
、分区容错性
。
CAP 想说一件什么事情,它想说咱们这个分布式系统里边,比如我们有三个节点,一号、二号、三号节点,
我们现在想做一个事务,想成功都成功,想失败都失败。
或者我保存了一个值,那大家都得跟我一样。所以我们说的第一个一致性指的就是这个。
在我们分布式系统里边,比如我们这一二三号机器,假设我们都是数据库,想要保存一个数据,比如这个数字是八,那我们既然要保存八,那一号保存了八。
我们下一个请求可能要访问二号数据库,二号就也得有八,三号也得有八。
这就相当于我们一个分布式系统里边所有这个数据的备份。
比如我们准备把八号备份在三个机器里边,所有数据的这个备份在同一个时刻是否都有同样的值。
比如我一号机器,我说八成功了,那你再来访问二号信息,结果你拿的刚才数据是七,那这个就不一致了。
所以我们说的一致性就是分布式系统里面所有的数据备份在同一时刻是一样的
还有我们的可用性,可用性就指的是我们一号机器,二号机器和三号机器。
如果有一个机器宕机了,我们整个集群还能不能响应客户端的所有操作
假设能响应,那就说明是可用的。
总结
面试前的“练手”还是很重要的,所以开始面试之前一定要准备好啊,不然也是耽搁面试官和自己的时间。
我自己是刷了不少面试题的,所以在面试过程中才能够做到心中有数,基本上会清楚面试过程中会问到哪些知识点,高频题又有哪些,所以刷题是面试前期准备过程中非常重要的一点。
面试题及解析总结
大厂面试场景
知识点总结
响应客户端的所有操作
假设能响应,那就说明是可用的。
总结
面试前的“练手”还是很重要的,所以开始面试之前一定要准备好啊,不然也是耽搁面试官和自己的时间。
我自己是刷了不少面试题的,所以在面试过程中才能够做到心中有数,基本上会清楚面试过程中会问到哪些知识点,高频题又有哪些,所以刷题是面试前期准备过程中非常重要的一点。
面试题及解析总结
[外链图片转存中…(img-srmwLNg0-1715136042860)]
大厂面试场景
[外链图片转存中…(img-p6DclcH9-1715136042861)]
知识点总结
[外链图片转存中…(img-WTZZQuRe-1715136042861)]