冲击双十一,我是怎么拿下蚂蚁金服的offer的,Java面试题分享

1、JVM面试题

1. 说说你对JVM内存模型的了解,每一个区的做用是什么?

栈区前端

  • 栈分为java虚拟机栈和本地方法栈
  • 重点是Java虚拟机栈,它是线程私有的,生命周期与线程相同。
  • 每一个方法执行都会建立一个栈帧,用于存放局部变量表,操做栈,动态连接,方法出口等。每一个方法从被调用,直到被执行完。对应着一个栈帧在虚拟机中从入栈到出栈的过程。
  • 一般说的栈就是指局部变量表部分,存放编译期间可知的8种基本数据类型,及对象引用和指令地址。局部变量表是在编译期间完成分配,当进入一个方法时,这个栈中的局部变量分配内存大小是肯定的。
  • 会有两种异常StackOverFlowError和 OutOfMemoneyError。当线程请求栈深度大于虚拟机所容许的深度就会抛出StackOverFlowError错误;虚拟机栈动态扩展,当扩展没法申请到足够的内存空间时候,抛出OutOfMemoneyError。
  • 本地方法栈为虚拟机使用到本地方法服务(native)

堆区java

  • 堆是被全部线程共享的一块区域,在虚拟机启动时建立,惟一目的存放对象实例。
  • 堆被划分红两个不一样的区域:新生代(Young)、老年代(Old)。
  • 新生代又被划分为三个区域:Eden和两个幸存区(From survivor 和 To survivor)。
  • 新生代主要存储新建立的对象和还没有进入老年代的对象。老年代存储通过屡次新生代GC(Minor GC)后仍然存活的对象。
  • 会有异常OutOfMemoneyError

方法区android

  • 被全部线程共享的区域,用于存放已被虚拟机加载的类信息,常量,静态变量等数据。被Java虚拟机描述为堆的一个逻辑部分。有时候也称它为永久代(permanment generation)
  • 垃圾回收不多光顾这个区域,不过也是须要回收的,主要针对常量池回收,类型卸载。
  • 常量池用于存放编译期生成的各类字节码和符号引用,常量池具备必定的动态性,里面能够存放编译期生成的常量;运行期间的常量也能够添加进入常量池中,好比string的intern()方法。

程序计数器ios

  • 当前线程所执行的行号指示器。经过改变计数器的值来肯定下一条指令,好比循环,分支,跳转,异常处理,线程恢复等都是依赖计数器来完成。
  • Java虚拟机多线程是经过线程轮流切换并分配处理器执行时间的方式实现的。为了线程切换能恢复到正确的位置,每条线程都须要一个独立的程序计数器,因此它是线程私有的。
  • 惟一一块Java虚拟机没有规定任何OutofMemoryError的区块。

2. JVM什么状况下会发生栈内存溢出

类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,而后在堆区建立一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,而且向Java程序员提供了访问方法区内的数据结构的接口。程序员

3. 类的生命周期

类的生命周期包括这几个部分,加载、链接、初始化、使用和卸载面试

  • 加载,查找并加载类的二进制数据,在Java堆中也建立一个java.lang.Class类的对象
  • 链接,链接又包含三块内容:验证、准备、初始化。1)验证,文件格式、元数据、字节码、符号引用验证;2)准备,为类的静态变量分配内存,并将其初始化为默认值;3)解析,把类中的符号引用转换为直接引用
  • 初始化,为类的静态变量赋予正确的初始值
  • 使用,new出对象程序中使用
  • 卸载,执行垃圾回收

4. JVM对象分配规则

  • 对象优先分配在Eden区,若是Eden区没有足够的空间时,虚拟机执行一次Minor GC。
  • 大对象直接进入老年代(大对象是指须要大量连续内存空间的对象)。这样作的目的是避免在Eden区和两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)。
  • 长期存活的对象进入老年代。虚拟机为每一个对象定义了一个年龄计数器,若是对象通过了1次Minor GC那么对象会进入Survivor区,以后每通过一次Minor GC那么对象的年龄加1,知道达到阀值对象进入老年区。
  • 动态判断对象的年龄。若是Survivor区中相同年龄的全部对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象能够直接进入老年代。
  • 空间分配担保。每次进行Minor GC时,JVM会计算Survivor区移至老年区的对象的平均大小,若是这个值大于老年区的剩余值大小则进行一次Full GC,若是小于检查HandlePromotionFailure设置,若是true则只进行Monitor GC,若是false则进行Full GC。

5. JVM如何判断对象是否存活

判断对象是否存活通常有两种方式:算法

  • 引用计数:每一个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时能够回收。此方法简单,没法解决对象相互循环引用的问题。
  • 可达性分析(Reachability Analysis):从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证实此对象是不可用的,不可达对象。

6. 介绍一下GC算法有哪些

GC最基础的算法有三种:标记 -清除算法、复制算法、标记-压缩算法,咱们经常使用的垃圾回收器通常都采用分代收集算法。spring

  • 标记 -清除算法,“标记-清除”(Mark-Sweep)算法,如它的名字同样,算法分为“标记”和“清除”两个阶段:首先标记出全部须要回收的对象,在标记完成后统一回收掉全部被标记的对象。
  • 复制算法,“复制”(Copying)的收集算法,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另一块上面,而后再把已使用过的内存空间一次清理掉。
  • 标记-压缩算法,标记过程仍然与“标记-清除”算法同样,但后续步骤不是直接对可回收对象进行清理,而是让全部存活的对象都向一端移动,而后直接清理掉端边界之外的内存
  • 分代收集算法,“分代收集”(Generational Collection)算法,把Java堆分为新生代和老年代,这样就能够根据各个年代的特色采用最适当的收集算法。

7. JVM有哪些垃圾回收器

  • Serial收集器,串行收集器是最古老,最稳定以及效率高的收集器,可能会产生较长的停顿,只使用一个线程去回收。
  • ParNew收集器,ParNew收集器其实就是Serial收集器的多线程版本。
  • Parallel收集器,Parallel Scavenge收集器相似ParNew收集器,Parallel收集器更关注系统的吞吐量。
  • Parallel Old 收集器,Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法
  • CMS收集器,CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。
  • G1收集器,G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高几率知足GC停顿时间要求的同时,还具有高吞吐量性能特征

8. JVM经常使用调优命令

Sun JDK监控和故障处理命令有jps jstat jmap jhat jstack jinfosql

  • jps,JVM Process Status Tool,显示指定系统内全部的HotSpot虚拟机进程。
  • jstat,JVM statistics Monitoring是用于监视虚拟机运行时状态信息的命令,它能够显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
  • jmap,JVM Memory Map命令用于生成heap dump文件
  • jhat,JVM Heap Analysis Tool命令是与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,能够在浏览器中查看
  • jstack,用于生成java虚拟机当前时刻的线程快照。
  • jinfo,JVM Configuration info 这个命令做用是实时查看和调整虚拟机运行参数。

9. JVM经常使用性能调优参数

  • Xss:规定了每一个线程虚拟机栈的大小
  • Xms:堆的初始值
  • Xmx:堆能达到的最大值

10. Java内存模型中堆和栈的区别

  • 管理方式数据库

    • 栈自动释放,堆须要GC
  • 空间大小

    • 栈比堆小
  • 碎片相关

    • 栈产生的碎片远小于堆
  • 分配方式

    • 栈支持静态和动态分配,而堆仅支持动态分配
  • 效率

    • 栈的效率比堆高

11. JVM中有几种类加载器

类加载器负责读取 Java 字节代码,并转换成java.lang.Class类的一个实例;有如下几张类加载去:

  • 启动类加载器(Bootstrap ClassLoader):Java应用启动时,加载$JAVA_HOME/lib或 -Xbootclasspath指定的路径中的类文件;
  • 扩展类加载器(Extension ClassLoaser):由sun.misc.Launcher$ExtClassLoader实现,负责加载$JAVA_HOME/lib/ext或java.ext.dirs指定路径的类库;
  • 应用程序类加载器(Application ClassLoader):又称系统类加载器,由sun.misc.Launcher$AppClassLoader实现,是ClassLoader.getSystemClassLoader()的返回值。
  • 自定义类加载器须要继承抽象类ClassLoader,实现findClass方法,该方法会在loadClass调用的时候被调用,findClass默认会抛出异常。

    • findClass方法表示根据类名查找类对象
    • loadClass方法表示根据类名进行双亲委托模型进行类加载并返回类对象
    • loadClass方法表示根据类名进行双亲委托模型进行类加载并返回类对象

12. 什么是双亲委派模型

  • 双亲委托模型的工做过程是:若是一个类加载器收到了类加载的请求,它首先不会本身去尝试加载这个类,而是把这个请求委托给父类加载器(父子关系由组合(不是继承)来实现)去完成,每个层次的类加载器都是如此, 所以全部的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈本身没法完成这个加载请求(它的搜索范围中没有找到所须要加载的类)时, 子加载器才会尝试本身去加载。
  • 使用双亲委托机制的好处是:

    • 避免同一个类被屡次加载;
    • 每一个加载器只能加载本身范围内的类;

13. 类加载过程

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)7个阶段。其中准备、验证、解析3个部分统称为链接(Linking)

加载、验证、准备、初始化和卸载这5个阶段的顺序是肯定的,类的加载过程必须按照这种顺序循序渐进地开始,而解析阶段则不必定:它在某些状况下能够在初始化阶段以后再开始,这是为了支持Java语言的运行时绑定(也称为动态绑定或晚期绑定)。如下陈述的内容都已HotSpot为基准。

14. 栈溢出的缘由

  • 是否有递归调用
  • 是否有大量循环或死循环
  • 全局变量是否过多
  • 数组、List、map数据是否过大

15. 方法区溢出的缘由

  • 动态生成大量Class
  • 大量JSP或动态产生JSP文件(JSP第一次运行时须要编译为Java类)

2、消息中间件面试题

1. 说说RabbitMQ的结构

  • Brocker:消息队列服务器实体。
  • Exchange:消息交换机,用于接收、分配消息。指定消息按什么规则,路由到哪一个队列。
  • Queue:消息队列,用于存储生产者的消息。每一个消息都会被投入到一个或者多个队列里。
  • Binding Key:绑定关键字,用于把交换器的消息绑定到队列中,它的做用是把exchange和queue按照路由规则binding起来。
  • Routing Key:路由关键字,用于把生产者的数据分配到交换器上。exchange根据这个关键字进行消息投递。
  • Vhost:虚拟主机,一个broker里能够开设多个vhost,用做不用用户的权限分离。
  • Producer:消息生产者,就是投递消息的程序。
  • Consumer:消息消费者,就是接受消息的程序。
  • Channel:信道,消息推送使用的通道。可创建多个channel,每一个channel表明一个会话任务。

2. RabbitMQ交换器种类

  • Direct exchange(直连交换机):直连型交换机(direct exchange)是根据消息携带的路由键(routing key)将消息投递给对应队列的,步骤以下:

    • 将一个队列绑定到某个交换机上,同时赋予该绑定一个路由键(routing key)
    • 当一个携带着路由值为R的消息被发送给直连交换机时,交换机会把它路由给绑定值一样为R的队列。
  • Fanout exchange(扇型交换机):扇型交换机(funout exchange)将消息路由给绑定到它身上的全部队列。不一样于直连交换机,路由键在此类型上不启任务做用。若是N个队列绑定到某个扇型交换机上,当有消息发送给此扇型交换机时,交换机会将消息的发送给这全部的N个队列
  • Topic exchange(主题交换机):主题交换机(topic exchanges)中,队列经过路由键绑定到交换机上,而后,交换机根据消息里的路由值,将消息路由给一个或多个绑定队列。

    • 扇型交换机和主题交换机异同:
    • 对于扇型交换机路由键是没有意义的,只要有消息,它都发送到它绑定的全部队列上
    • 对于主题交换机,路由规则由路由键决定,只有知足路由键的规则,消息才能够路由到对应的队列上
  • Headers exchange(头交换机):相似主题交换机,可是头交换机使用多个消息属性来代替路由键创建路由规则。经过判断消息头的值可否与指定的绑定相匹配来确立路由规则。 此交换机有个重要参数:”x-match”。

    • 当”x-match”为“any”时,消息头的任意一个值被匹配就能够知足条件
    • 当”x-match”设置为“all”的时候,就须要消息头的全部值都匹配成功

3. RabbitMQ队列与消费者的关系

  • 一个队列能够绑定多个消费者;
  • 队列分发消息将以轮询的方式分发,每条消息只会分发给一个订阅的消费者;
  • 消费者收到消息以后默认是自动确认,能够设置手动确认,保证消费者消费了消息。

4. 如何保证消息的顺序性

  • RabbitMQ

    • 拆分多个queue,每一个queue一个consumer,就是多一些queue而已
    • 一个queue可是对应一个consumer,而后这个consumer内部用内存队列作排队,而后分发给底层不一样的worker来处理
  • kafka

    • 一个topic,一个partition,一个consumer,内部单线程消费,写N个内存queue,而后N个线程分别消费一个内存queue便可

3、数据库面试题

1. InnoDB中的事务隔离级别

SQL标准中的事务四种隔离级别

  • 未提交读(Read Uncommitted):可能出现脏读(可能读取到其余会话中未提交事务修改的数据)、不可重复读、幻读
  • 提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)
  • 可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,可是还存在幻象读
  • 串行读(Serializable):彻底串行化的读,每次读都须要得到表级共享锁,读写相互都会阻塞

2. 解释下脏读、不可重复读、幻读

  • 脏读:指当一个事务正字访问数据,而且对数据进行了修改,而这种数据尚未提交到数据库中,这时,另一个事务也访问这个数据,而后使用了这个数据。由于这个数据尚未提交那么另一个事务读取到的这个数据咱们称之为脏数据。依据脏数据所作的操做肯能是不正确的。
  • 不可重复读:指在一个事务内,屡次读同一数据。在这个事务尚未执行结束,另一个事务也访问该同一数据,那么在第一个事务中的两次读取数据之间,因为第二个事务的修改第一个事务两次读到的数据多是不同的,这样就发生了在一个事物内两次连续读到的数据是不同的,这种状况被称为是不可重复读。
  • 幻读:一个事务前后读取一个范围的记录,但两次读取的纪录数不一样,咱们称之为幻象读(两次执行同一条 select 语句会出现不一样的结果,第二次读会增长一数据行,并无说这两次执行是在同一个事务中)

3. MyISAM和InnoDB二者之间的区别

InnoDB是一个事务型的存储引擎,支持回滚,设计目标是处理大数量数据时提供高性能的服务,它在运行时会在内存中创建缓冲池,用于缓冲数据和索引。

优势

  • 支持事务处理、ACID事务特性;
  • 实现了SQL标准的四种隔离级别;
  • 支持行级锁和外键约束;
  • 能够利用事务日志进行数据恢复。
  • 锁级别为行锁,行锁优势是适用于高并发的频繁表修改,高并发是性能优于 MyISAM。缺点是系统消耗较大。
  • 索引不只缓存自身,也缓存数据,相比 MyISAM 须要更大的内存。

缺点

  • 由于它没有保存表的行数,当使用COUNT统计时会扫描全表。

MyISAM 是 MySQL 5.5.5 以前的默认引擎,它的设计目标是快速读取。

优势

  • 高性能读取;
  • 由于它保存了表的行数,当使用COUNT统计时不会扫描全表;

缺点

  • 锁级别为表锁,表锁优势是开销小,加锁快;缺点是锁粒度大,发生锁冲动几率较高,容纳并发能力低,这个引擎适合查询为主的业务。
  • 此引擎不支持事务,也不支持外键。
  • INSERT和UPDATE操做须要锁定整个表;
  • 它存储表的行数,因而COUNT时只须要直接读取已经保存好的值而不须要进行全表扫描。

适用场景

  • MyISAM适合:

    • 作不少count 的计算;
    • 插入不频繁,查询很是频繁;
    • 没有事务。
  • InnoDB适合:

    • 可靠性要求比较高,或者要求事务;
    • 表更新和查询都至关的频繁,而且表锁定的机会比较大的状况

4. 说说事务的四种特性(ACID)

  • 原子性(Atomicity):一个事务必须被视为一个不可分割的最小工做单元,整个事务中的全部操做要么所有提交成功,要么所有失败回滚,对于一个事务来讲,不能够只执行其中的一部分操做。
  • 一致性(Consistency):数据库老是从一个一致性的状态转到另外一个一致性的状态。 拿转帐来讲,假设用户A和用户B二者的钱加起来一共是5000,那么无论A和B之间如何转帐,转几回帐,事务结束后两个用户的钱加起来应该还得是5000,这就是事务一致性。
  • 隔离性(Isolation):一般来讲,一个事务所作的修改在最终提交以前,对其余事务是不可见的。
  • 持久性(Durability):一旦事务提交,则其所作的修改就会永久的保存到数据库中。不会由于系统故障等状况而丢失所作的修改。

4、NoSQL面试题

1. Memcache和Redis的区别

Memcache

  • 支持简单数据类型
  • 不支持数据持久化存储
  • 不支持主从
  • 不支持分片

Redis

  • 数据类型丰富
  • 支持数据磁盘持久化存储
  • 支持主从
  • 支持分片

2. 为何Redis能这么快

  • 彻底基于内存,绝大部分请求是纯粹的内存操做,执行效率高
  • 数据结构简单,对数据操做也简单
  • 使用多路I/O复用模型,非阻塞IO
  • 采用单线程,单线程也能处理高并发请求,想多核也能够启动多实例

3. 说说你用过的Redis的数据类型

  • String:最基本的数据类型,二进制安全
  • Hash:String元素组成的字典,适合用于存储对象
  • List:列表,按照String元素插入顺序排序
  • Set:String元素组成的无序集合,经过Hash表实现,不容许重复
  • Sorted Set:经过分数来为集合中的成员进行从小到大的排序
  • 用于计数的HyperLogLog(非重点,前面五个尽可能说出来)

4. 如何经过Redis实现分布式锁

SET key value [EX seconds] [PX milliseconds] [NX|XX]

  • EX seconds:设置键的过时时间为second秒
  • PX milliseconds:设置键的过时时间为millisecond毫秒
  • NX:只在键不存在时,才对键进行设置操做
  • XX:只在键已经存在时,才对键进行设置操做
  • SET操做成功完成时,返回OK,不然返回nil

5. Redis中大量的key同时过时的注意事项

  • 现象:集中过时,因为清楚大量的key很耗时,会出现短暂的卡顿现象
  • 解决方案:在设置key的过时时间的时候,给每一个key加上随机值

6. 如何使用Redis作异步队列

使用List做为队列,RPUSH生产消息,LPOP消费消息

缺点:没有等待队列里面有值就直接消费

解决方案

  • 能够经过在应用层引入Sleep机制去调用LPOP重试
  • BLPOP key [key ...] timeout:阻塞直到队列有消息或者超时,缺点是只能供一个消费者消费
  • pub/sub:主题订阅者模式,缺点:消息的发布是无状态的,没法保证可达

5、分布式面试题

1. 说说SpringCloud的工做原理

Spring Cloud是一个全家桶式的技术栈,包含了不少组件,其中比较核心的有Eureka、Ribbon、Feign、Hystrix、Zuul这几个组件。

  • Eureka是微服务架构中的注册中心,专门负责服务的注册与发现。每一个服务中都有一个Eureka Client组件,这个组件专门负责将这个服务的信息注册到Eureka Server中。说白了,就是告诉Eureka Server,本身在哪台机器上,监听着哪一个端口。而Eureka Server是一个注册中心,里面有一个注册表,保存了各服务所在的机器和端口号。服务调用者调用对应服务时,它的Eureka Client组件会找Eureka Server查找对应的服务信息进行调用,而后就能够把这些相关信息从Eureka Server的注册表中拉取到本身本地缓存起来,方便下次调用。

    • Eureka Client:负责将这个服务的信息注册到Eureka Server中
    • Eureka Server:注册中心,里面有一个注册表,保存了各个服务所在的机器和端口号
  • Feign基于动态代理机制,根据注解和选择的机器,拼接请求URL地址,发起请求。Feign的一个关键机制就是使用了动态代理。

    • 首先,若是你对某个接口定义了@FeignClient注解,Feign就会针对这个接口建立一个动态代理
    • 接着你要是调用那个接口,本质就是会调用 Feign建立的动态代理,这是核心中的核心
    • Feign的动态代理会根据你在接口上的@RequestMapping等注解,来动态构造出你要请求的服务的地址
    • 最后针对这个地址,发起请求、解析响应
  • Ribbon的做用是负载均衡,会帮你在每次请求时选择一台机器,均匀的把请求分发到各个机器上。Ribbon的负载均衡默认使用的最经典的Round Robin轮询算法。并且,Ribbon是和Feign以及Eureka紧密协做,完成工做的。

    • 首先Ribbon从 Eureka Client里获取到对应的服务注册表,即知道了全部的服务都部署在了哪些机器上,在监听哪些端口号
    • 而后Ribbon就可使用默认的Round Robin轮询算法,从中选择一台机器
    • Feign就会针对这台机器,构造并发起请求
  • Hystrix是隔离、熔断以及降级的一个框架,发起请求是经过Hystrix的线程池来走的,不一样的服务走不一样的线程池,实现了不一样服务调用的隔离,避免了服务雪崩的问题
  • Zuul就是微服务网关,这个组件是负责网络路由的。通常微服务架构中都必然会设计一个网关在里面,像android、ios、pc前端、微信小程序、H5等等,不用去关心后端有几百个服务,就知道有一个网关,全部请求都往网关走,网关会根据请求中的一些特征,将请求转发给后端的各个服务。并且有了网关以后,能够作统一的降级、限流、认证受权、安全等功能。

2. Eureka的心跳时间

  • Eureka的客户端默认每隔30s会向eureka服务端更新实例,注册中心也会定时进行检查,发现某个实例默认90s内没有再收到心跳,会注销此实例。可是这些时间间隔是可配置的。
  • 不过注册中心还有一个保护模式,在这个保护模式下,他会认为是网络问题,不会注销任何过时的实例

3. Eureka的缺点

  • 不知足CAP的一致性
  • 中止维护了,2.0以后不开源

4. 说说分布式事务有哪些解决方案

  • 基于XA协议的两阶段提交方案

    • 第一阶段是表决阶段,全部参与者都将本事务可否成功的信息反馈发给协调者;第二阶段是执行阶段,协调者根据全部参与者的反馈,通知全部参与者,步调一致地在全部分支上提交或者回滚。
    • 缺点:两阶段提交方案锁定资源时间长,对性能影响很大,基本不适合解决微服务事务问题。
  • TCC方案

    • TCC方案实际上是两阶段提交的一种改进。其将整个业务逻辑的每一个分支显式的分红了Try、Confirm、Cancel三个操做。Try部分完成业务的准备工做,confirm部分完成业务的提交,cancel部分完成事务的回滚。
    • 事务开始时,业务应用会向事务协调器注册启动事务。以后业务应用会调用全部服务的try接口,完成一阶段准备。以后事务协调器会根据try接口返回状况,决定调用confirm接口或者cancel接口。若是接口调用失败,会进行重试。

      • 缺点:一、对应用的侵入性强。业务逻辑的每一个分支都须要实现try、confirm、cancel三个操做,应用侵入性较强,改形成本高。 二、实现难度较大。须要按照网络状态、系统故障等不一样的失败缘由实现不一样的回滚策略。为了知足一致性的要求,confirm和cancel接口必须实现幂等。
  • 基于可靠消息的最终一致性方案

    • 消息一致性方案是经过消息中间件保证上、下游应用数据操做的一致性。基本思路是将本地操做和发送消息放在一个事务中,保证本地操做和消息发送要么二者都成功或者都失败。下游应用向消息系统订阅该消息,收到消息后执行相应操做。
    • 消息方案从本质上讲是将分布式事务转换为两个本地事务,而后依靠下游业务的重试机制达到最终一致性。基于消息的最终一致性方案对应用侵入性也很高,应用须要进行大量业务改造,成本较高。
  • GTS

    • GTS是一款分布式事务中间件,由阿里巴巴中间件部门研发,能够为微服务架构中的分布式事务提供一站式解决方案。
    • 优势:性能超强、应用侵入性极低、完整解决方案、容错能力强

5. rpc和http的区别

  • RPC主要是基于TCP/IP协议,而HTTP服务主要是基于HTTP协议
  • RPC要比http更快,虽然底层都是socket,可是http协议的信息每每比较臃肿
  • RPC实现较为复杂,http相对比较简单
  • 灵活性来看,http更胜一筹,由于它不关心实现细节,跨平台、跨语言。
  • 若是对效率要求更高,而且开发过程使用统一的技术栈,那么用RPC仍是不错的。
  • 若是须要更加灵活,跨语言、跨平台,显然http更合适

6、经常使用框架面试题

1. 说说Spring事务什么状况下才会回滚

当所拦截的方法有指定异常抛出,事务才会自动进行回滚。默认状况下是捕获到方法的RuntimeException异常,也就是说抛出只要属于运行时的异常(即RuntimeException及其子类)都能回滚;但当抛出一个不属于运行时异常时,事务是不会回滚的。若是是其余异常想要实现回滚,能够进行配置。

2. 说说Spring事务的传播属性

事务的传播性通常在事务嵌套时候使用,好比在事务A里面调用了另一个使用事务的方法,那么这俩个事务是各自做为独立的事务执行提交,仍是内层的事务合并到外层的事务一块提交那,这就是事务传播性要肯定的问题。spring支持7种事务传播行为:

  • PROPAGATION_REQUIRED – 支持当前事务,若是当前没有事务,就新建一个事务。这是最多见的选择。
  • PROPAGATION_SUPPORTS – 支持当前事务,若是当前没有事务,就以非事务方式执行。
  • PROPAGATION_MANDATORY – 支持当前事务,若是当前没有事务,就抛出异常。
  • PROPAGATION_REQUIRES_NEW – 新建事务,若是当前存在事务,把当前事务挂起。
  • PROPAGATION_NOT_SUPPORTED – 以非事务方式执行操做,若是当前存在事务,就把当前事务挂起。
  • PROPAGATION_NEVER – 以非事务方式执行,若是当前存在事务,则抛出异常。
  • PROPAGATION_NESTED – 若是当前存在事务,则在嵌套事务内执行。若是当前没有事务,则进行与PROPAGATION_REQUIRED相似的操做。

备注:经常使用的两个事务传播属性是1和4,即PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW

3. 说说Spring事务的隔离性

事务的隔离性是指多个事务并发执行的时候相互之间不受到彼此的干扰。

事务的隔离级别也分为四种,由低到高依次分别为:read uncommited(读未提交)、read commited(读提交)、read repeatable(读重复)、serializable(序列化),这四个级别能够逐个解决脏读、不可重复读、幻读这几类问题。

  • read uncommited:是最低的事务隔离级别,它容许另一个事务能够看到这个事务未提交的数据。
  • read commited:保证一个事物提交后才能被另一个事务读取。另一个事务不能读取该事物未提交的数据。
  • repeatable read:这种事务隔离级别能够防止脏读,不可重复读。可是可能会出现幻象读。它除了保证一个事务不能被另一个事务读取未提交的数据以外还避免了如下状况产生(不可重复读)。
  • serializable:这是花费最高代价但最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读以外,还避免了幻读。
  • DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.

4. 说说Spring事务的特性

事务特性分为四个:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持续性(Durability)简称ACID。

  • 原子性(Atomicity):事务是数据库逻辑工做单元,事务中包含的操做要么都执行成功,要么都执行失败。
  • 一致性(Consistency):事务执行的结果必须是使数据库数据从一个一致性状态变到另一种一致性状态。当事务执行成功后就说数据库处于一致性状态。若是在执行过程当中发生错误,这些未完成事务对数据库所作的修改有一部分已写入物理数据库,这是数据库就处于不一致状态。
  • 隔离性(Isolation):一个事务的执行过程当中不能影响到其余事务的执行,即一个事务内部的操做及使用的数据对其余事务是隔离的,并发执行各个事务之间无不干扰。
  • 持续性(Durability):即一个事务执一旦提交,它对数据库数据的改变是永久性的。以后的其它操做不该该对其执行结果有任何影响。

5. 说说你对SpringIOC容器的理解

SpringIOC负责建立对象,管理对象(经过依赖注入(DI),装配对象,配置对象,而且管理这些对象的整个生命周期。

6. 什么是Spring的依赖注入

依赖注入,是IOC的一个方面。这概念是说你不用建立对象,而只须要描述它如何被建立。你不在代码里直接组装你的组件和服务,可是要在配置文件里描述哪些组件须要哪些服务,以后一个容器(IOC容器)负责把他们组装起来。

7. IOC(依赖注入)方式

  • 构造器依赖注入:构造器依赖注入经过容器触发一个类的构造器来实现的,该类有一系列参数,每一个参数表明一个对其余类的依赖。
  • Setter方法注入:Setter方法注入是容器经过调用无参构造器或无参static工厂方法实例化bean以后,调用该bean的setter方法,即实现了基于setter的依赖注入。
  • 用构造器参数实现强制依赖,setter方法实现可选依赖。

8. Springboot启动过程

  • 构造SpringApplication的实例
  • 调用SpringApplication.run()方法

    • 构造SpringApplicationRunListeners 实例
    • 发布ApplicationStartedEvent事件
    • SpringApplicationRunListeners 实例准备环境信息
    • 建立ApplicationContext对象
    • ApplicationContext实例准备环境信息
    • 刷新的上下文

9. spring的bean的生命周期

  • Spring 容器根据配置中的 bean 定义中实例化 bean。
  • Spring 使用依赖注入填充全部属性,如 bean 中所定义的配置。
  • 若是 bean 实现 BeanNameAware 接口,则工厂经过传递 bean 的 ID 来调用 setBeanName()。
  • 若是 bean 实现 BeanFactoryAware 接口,工厂经过传递自身的实例来调用 setBeanFactory()。
  • 若是存在与 bean 关联的任何 BeanPostProcessors,则调用 preProcessBeforeInitialization() 方法。
  • 若是为 bean 指定了 init 方法( 的 init-method 属性),那么将调用它。
  • 最后,若是存在与 bean 关联的任何 BeanPostProcessors,则将调用 postProcessAfterInitialization() 方法。
  • 若是 bean 实现 DisposableBean 接口,当 spring 容器关闭时,会调用 destory()。
  • 若是为 bean 指定了 destroy 方法( 的 destroy-method 属性),那么将调用它。
咱们这里描述的是应用Spring上下文Bean的生命周期,若是应用Spring的工厂也就是BeanFactory的话去掉第5步就Ok了。

11. spring事件的实现原理,写出经常使用的几个事件

写在最后

本次面试题分享到此为止,限于篇幅,无法在这里给你们分享更多的面试题; 以前不少粉丝一直私信我让我整理一些面试题,近些天终于整理好了,笔者整理了一份包含Kafka、Mysql、Tomcat、Docker、Spring、MyBatis、Nginx、Netty、Dubbo、Redis、Netty、Spring cloud、分布式、高并发、性能调优、微服务等架构技术的面试题和部分视频学习资料;

须要的朋友点击下方传送门, 便可免费领取面试资料和视频学习资料

传送门

如下是部分面试题截图

相关文章
相关标签/搜索