1 Hystrix的状态有哪些
closed ->open:正常情况下熔断器为closed状态,当访问同一个接口次数超过设定阈值并且错误比例超过设置错误阈值的时候,就会打开熔断机制,这时候熔断状态从closed->open。
open -> half-open:当服务接口对应的熔断状态为open状态时候,所有服务调用方调用该服务方法的时候都是执行本地降级方法. Hystrix提供了一种测试策略,也就是设置了一个时间窗口,从熔断器状态变为open状态开始的一个事件窗口内,调用服务接口时候都委托服务降级方法进行执行.如果时间超过了时间窗口,则把熔断状态从open->half-open,这时候服务调用方调用服务接口的时候,就可以发起远程调用而不再使用本地降级接口,如果发起远程调用还是失败,则重新设置熔断状态为open状态,从新记录时间窗口开始时间.
half-open -> closed:当熔断器状态为half-open,这时候服务调用方调用服务接口的时候,就可以发起远程调用而不再使用本地降级接口,如果发起远程调用成功,则重新设置熔断器状态为closed状态.
2 什么是熔断降级
熔断机制是应对雪崩效应的一种微服务链路保护机制.当某个微服务不可用或者响应时间太长时,会进行服务降级,进而熔断该节点微服务的嗲用,快速返回"错误"的响应信息.
服务降级,一般是从整体符合考虑,就是当某个服务熔断之后,服务器将不在被调用,此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值.
3 SpringBoot如何实现自动配置
@SpringBootApplication注解中包含@EnableAutoConfiguration注解.
@EnableAutoConfiguration注解中使用了@Import({AutoConfigurationImportSelector.class})注解.
AutoConfigurationImportSelector类中读取,META-INF/Spring.factories配置文件中的所有自动配置类,并对其进行加载.
自动配置类是一个JavaConfig形式的Spring容器配置类,他能通过以Properties结尾命名类,读取在全局配置文件中配置的属性值
4 SpringBoot的核心注解?它主要由哪几个注解组成的?
@SpringBootApplication是SPringBoot的核心注解,主要组合包含了一下3个注解:
@SpringtConfiguration:组合了@Configuration注解,实现配置文件的功能.
@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项.
@componentScan:Spring组件扫描.
5 HashMap的数据结构
HashMap采用数组+链表+红黑树的方式保存数据.HashMap在查找数据时,根据HashMap的Hash值可以快速定位到数组的具体下标。但是在找到数组下标后需要对链表进行顺序遍历知道找到需要的数据.为了减少链表遍历的开销,Java8对HashMap进行了优化,将数据结构化为数组+链表+红黑树.如果链表长度大于阈值(8)数组长度超过64,则进行树化(将链表转为红黑树)会将此链表转为红黑树结构
6 HashMap添加元素的过程
1 首先判断数组是否为空,如果为空则需要对数组进行扩容
2 如果数组不为空,则通过数组长度-1与新增元素的key的hash值进行运算,得到数组的下标,通过下标获得该下标对应的数组元素
3 判断获得的元素是否为空,如果为空则使用新增的键-值 创建节点,将节点放在数组此位置上.
4 如果数组的元素不为空,则判断新增的元素的hash值和key值,是否与数组中第一个元素的hash值和key值相等,如果相等则用新的值替换老的值.
5 如果不相等,则判断数组元素是否是红黑树,如果是红黑树,则向红黑树中添加元素
6 如果不是红黑树,则对链表进行遍历,并且统计链表长度,如果链表中不包含要插入的键值对节点时,则该节点放在链表的最后.如果链表长度大于阈值(8)数组长度超过64,则进行树化(将链表转为红黑树).如果要插入的键值对存在,则用新的值替换老的值.
7 如果map中元素的个数大于扩容的阈值(数组长度*负载因子),则需要对数组进行扩容.
7 HashMap HashTable的区别?
HashMap和Hashtable都实现了Map接口,HashMap几乎可以等价于Hashtable
除了HashMap不是线程安全的,HashTable是线程安全的.
HashMap可以接受为null的键(key)和值(value),二HashTable则不行
8 hash的概念是什么?如何避免哈希冲突?
hash,是把任意长度的输入通过散列算法变换成固定长度的输出,该输出就是散列值
如何避免哈希冲突?
链地址法
将所有哈希地址相同的元素构成一个单链表,链地址法适用于经常进行插入和删除的情况
9 线程的创建方式有哪些?
创建线程只有一种方式就是构造Thread类,而实现线程的执行单元有两种方式.
方式一:实现Runnable接口的run方法,并把Runnable实例传递给Thread类.
方式二:重写Thread类的run方法.
10 线程的状态有哪些?
NEW:当常见一个线程对象,还没有调用start()方法.
RUNNABLE:调用了start()方法,不关线程是否被CPU执行,都处于RUNNABlE.
BLOCKED:线程等待获取对象的监视器锁时.处于BLOCKED状态时,线程无法被中断.
WAITING: 线程处于无线等待状态,除非被其他线程唤醒或者接收到中断信号.
TIME_WATING:定是等待,线程等待执行时间后会恢复到RUNNABLE状态.可以提前被唤醒或者终端.
TERMINATED:线程执行完毕.
11 线程池中构造方法的参数有哪些?有什么用?
corePoolSize指的是核心线程数:线程池在完成初始化后,默认情况下,线程池中并没有任何线程,线程池会等待有任务到来时,再创建新线程去执行任务.按任务提交到线程池后,首先会检查当前线程数是否达到了corePoolSize,如果没有达到的话,则会创建一个新线程来处理这个任务.
当线程数达到corePoolSize后,如果继续有任务被提交到线程池,会将任务缓存到工作队列中.如果队列也已满,则会去创建一个新线程来处理.线程池不会无限制的去创建新线程,他会有一个最大线程数量,这个数量由maximunPoolSize指定.
一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空线程会被销毁,这里的指定时间有keepAliveTime来设定.
有3中最常见的队列类型:
- 直接交接:SynchronousQueue
- 无界队列:LinkedBlockingQueue
- 有界队列:ArrayBlockingQueue
12 如何中断一个线程
interrupt通知线程要中断,不是强制,如果线程在执行完以后,才中断
stop 强制线程中断,线程中的内容没有执行完也会中断.
13 锁的分类
线程要不要锁住同步资源:
悲观锁(锁住) 乐观锁(不锁住)
多线程能否共享一把锁:
共享锁(可以) 独占锁(不可以)
多线程竞争时,是否排队:
公平锁(排队) 非公平锁(先尝试插队.插队失败再排队)
同一个线程是否可以重复获取同一把锁:
可重入锁(不可以) 不可重入锁(不可以)
是否可中断:
可中断锁(可以) 非可中断锁(不可以)
等锁的过程:
自旋锁 非自旋锁
14 sleep()方法和wait()方法有什么区别?
sleep方法可以让线程进入waitinfg状态,不占用CPU资源,但是不释放锁,直到规定时间后再执行,休眠期间如果被中断,会抛出异常并清除中断状态.sleep方法是线程中的方法.
用线程的wait方法线程会进入阻塞截断.wait方法会释放锁.wait方法是Object类中的方法.
另一个线程调用这个对象的notify()方法且刚好被唤醒的是本线程;
另一个线程调用这个对象的notifyAll()方法;
过了wait(long timeout)规定的超时时间,如果传入0就是永久等待
线程自身调用了interrupt()
15 关闭线程池的方法有哪些?他们有什么区别?
shutdown方法:停止线程池,会将线程池中已存在的任务执行完毕以后,在停止线程池,如果执行了shutdown方法以后,在向线程池中添加任务,线程池会抛出拒绝的异常.
shutdownNow:中断线程吃中正在运行的任务,将任务队列中的任务返回.
16 volatile关键字的作用是什么?
1.可见性: 读一个volatile变量之前,需要先使相应的本地缓存失效,这样就必须到主内存读取最新值,写一个volatile属性会立即刷入到主内存.
2.禁止指令重排序优化:解决单例双重锁乱序问题
17 ThreadLocal的作用有哪些?
场景1 每个线程需要一个独享的对象(通常是工具类,典型需要使用的类有SimpleDateFormat和Random)
场景2 每个线程内需要保存全局变量,可以让不同方法直接使用,避免参数传递的麻烦
18 线程中run方法和start方法的作用?
start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样.当调用run()方法的时候,只会在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程.
19 线程池的拒绝策略有哪些?
AbortPolicy:直接抛出异常
DiscardPolicy:直接丢弃
DiscardOldestPolicy:丢弃最老的任务
CallerRunsPolicy:提交任务的线程去执行该任务
20 CAS的原理?CAS的缺点
原理
compare and swap
CAS有是三个操作数:内存值V 预期值A 要修改的值B,并且当预期值A与内存值V相同时,才向内存值修改为B,否则什么都不做.最后返回现在的值.CAS最终利用CPU的特殊指令,一个指令可以做多个事情.
缺点
ABA问题
假设原来a的值是5,线程3想将a的值修改为10,在线程3的执行过程中,还没有来的及更新a的值.线程1先将a的值修改为了7,线程2将a的值修改为了5.线程3此时去修改a的值,发现a的值是5.线程3就可以修改a的值,将值修改为10.但是此时能够修改数据应该是不合理的,因为线程C在修改a的值之前,已经有线程修改了a的值,可以添加version版本号的方式解决该问题
自旋时间过长
21 CyclicBarrier和CountDownLatch的区别
作用不同:CyclicBarrier要等固定数量的线程都到达了栅栏位置才能继续执行,而CountDownLatch只需要等待数字到0,也就是说,CountDownLatch用于事件,但是CyclicBarrier是用于线程的.
可重用性不同:CountDownLatch在倒数到0并触发门闩打开后,就不能再次使用了,除非新建新的实例;二CyclicBarrier可以重复使用.
22 ReentrantLock与synchronzied的区别
1 synchronized来说,他是java语言的关键字,是原生语法层面的互斥,需要jvm实现.而ReentrantLock他是JDK1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成
2 ReentrantLock类提供了一些高级功能,主要由一下3项:
等待可以中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况.
公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数式创建得非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好.
23 HashSet新增元素的过程
1 HashSet在新增数据的时候,先判断内部的数组是否为空,如果数组为空,则初始化数组.
2 如果数组不为空,获得向HashSet中添加的元素哈希码(元素的hashcode方法获得哈希码)在经过一系列的算法,计算出该元素储存在HashSet数组中的位置
3 在HashSet的数组中查找该位置上是否有元素,如果该位置上没有元素,则此元素就可以放到该位置上.
4 如果该位置有元素,则比较新增元素与该位置上的元素的哈希码,如果哈希码不同,新增的元素放在该位置的链表的末尾.
5 如果元素的哈希码相同,新增的元素嗲用equals方法和原来的元素进行比较,如果equals方法的案回执是false,表示两个元素不相等,新增的元素放在该位置的链表的末尾.
6 如果equals方法的返回值相同,则新增失败.
24 mybatis中#{}和${}的区别
${} 类似于通过替换后生成sql语句,类似于JDBC中的Statement,不能防止sql语句注入
#{} 可以绑定变量,可以防止sql注入攻击,类似于JDBC中的PreparedStatement
25 Ribbom负载均衡的策略有哪些
- RoundRobinRule:轮询策略.按照server顺序返回server,再返回之前会判断服务是否可用.如果不可用则尝试返回下一个服务实例,如果超过10次,返回的服务都不可用,则返回一个空的server
- RandomRule:随机策略,随机返回一个server.如果随机到的server为null或者不可用的话,会循环不停的选取.
- RetryRule:默认继承RoundRobinRule,RetryRule会每次选取之后,判断server是否可用,如果不可用则采用轮询的方式,返回下一个服务,再去判断服务是否可用,与RoundRobinRule不同的是,RoundRobinRule是超过10次不可用,则返回返回一个空的server.而RetryRule是500ms内不停的选取判断.
- BestAvailableRule:最小连接数策略.遍历serverList,选取出可用的且连接数最小的一个server.刚开始时假设有3个server.每个server上连接数为0.此时会选择第一个server返回.现在第一个server上的连接数是1,第二个server上的连接数为0,第三个server上的连接数为0.第二次在获得server时,会返回第二个server.第三次获得时返回最后一个server以此类推.
- AvailabilityFilterRule:可用过滤策略.扩展了轮询策略,会先通过轮询选取一个server,再去判断server是否可用,当前连接数是否超限,都成功再返回.
26 SpringBoot项目如何处理异常处理
1 创建异常处理类,在该类上添加@RestControllerAdvice注解
2 在类中添加异常处理方法,在方法上创建@ExceptionHandler注解,value属性的值是异常的类型.在异常处理方法中封装错误信息,返回json格式数据
27 说一说Map中的Hash算法
如果key为null,返回0,不为null,则通过(h=key.hashCode())^(h>>>16)工时计算得到哈希值
该公式通过hashCode的高16位异或低16位得到哈希值,主要从性能、哈希碰撞角度考虑,减少系统开销,不会造成因为高位没有参与下标计算从而引起的碰撞。
28 数据库的隔离级别有哪些
读未提交会产生:脏读 不可重复度 幻读等问题
当数据库使用READ UNCOMMITTED隔离级别时,一个事务在执行过程中可以看到其他事务没有提交的新插入的记录和更新的记录
读已提交会产生:不可重复度 幻读等问题。
当数据库系统使用READ COMMITTED隔离级别时,一个事务在执行过程中能看到其他事务已经提交的对新增和更新的记录。
可重复读会产生:幻读
当数据库使用REPEATABLE READ隔离级别时,一个事务在执行过程中不能看到其他事务已经提交的更新记录,但是可以看到其他事务已经提交的新增的记录。MYSQL数据库的隔离级别时可重复读。但是MYSQL的可重复读不会出现幻读。
串行化
数据库系统使用SERIALIZABLE隔离级别时,一个事物在执行过程中完全看不到其他事务对数据库所做的更新。当两个事务同时操作数据库相同数据时,如果第一个事务已经在访问改数据,第二个事务只能停下来等待,必须等到第一个事务结束后才能恢复运行。因此这两个事务实际上是串行化方式运行。
29 隔离级别产生的问题
脏读(Dirty read):一个事务读到了另一个事务未提交的数据。
不可重复读(Unrepeatableread):指在一个事务内多次读同一个数据。在这个事务还没有结束时,另一个事务也访问该数据。name,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
幻读与不可重复读类似。它发生在一个事务读取了几行数据,接着另一个并发事务插入了一些数据时。在随后的查询中,第一个事务就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
30 如何理解分布式和集群
集群
集群是指将多台服务器集中在一起,每台服务器都实现相同的业务,做相同的事情。
分布式
分布式是将多台服务器集中在一起,每台服务器都实现总体中的不同业务,做不同的事情。
31 事务的特性
原子性(Atomicity)
十五中的所有操作要么全部执行,要么都不执行。如果事务没有原子性的保证,那么在发生系统故障的情况下,数据库就有可能处于不一致状态。
一致性(Consistency)
主要强调的是,如果在执行事务之前数据是一只的,那么在执行事务之后数据库也还是一直的。所谓一致性简单地说就是数据库中数据的完整性,包括他们的正确性。
隔离性(Isolation)
几十多个事务并发(同时)执行,每个事务都感觉不到系统中有其他事务在执行,因而他就能保证数据库的一致性。
持久性(Durability)
事务成功执行后他对数据库的修改时永久的,即使系统出现故障也不受影响。
32 数据库设计的三大范式有哪些?
第一范式(确保每列保持原子性)第一范式是最基本的范式。如果数据库表中的所有字段都是不可分解的原子值,就说明该数据库满足了第一范式。
第二范式在第一范式的基础上更近一层。第二范式需要确保数据库表中的每一列都和主键相关。就是说在一个数据库中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库中。
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能简介相关。
33 Redis中基本类型有哪些?
string
list
set
zset
hash
34 Redis中删除过期数据的策略?
Redis采用定期删除和惰性删除的方式
定期删除,指的是redis默认是每个100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。
惰性删除。在你获得某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。并不是key到时见就被删除掉,而是你查询这个key的时候,redis再懒惰的检查一下。
35 Redis中的内存淘汰机制
Redis的内存太高太策略是指在Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据。
noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key
allkeys-lfu:当内存不足以容纳新写入数据时:在键空间中,移除使用次数最少的key
allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。
volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的。
volatile-lfu:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除使用次数最少的key
volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key
volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除
36 SpringCould组件有哪些
Nacos 当做服务注册发布中心 服务的配置中心
OpenFeign 用于远程服务调用
Sentinel 流量控制、熔断降级、系统负载保护
Gateway 网关
Ribbon 负载均衡工具
Seata 分布式事务解决方案
37 SpringMVC的运行流程
第一步:发起请求到前端控制器
第二步:前端控制器请求HandlerMapping查找Handler
第三步:处理器映射器HandlerMapping向前端控制器返回Handler
第四步:前端控制器调用处理器适配器去执行Handler
第五步:处理器适配器HandlerAdapter将会根据适配的结果去执行Handler
第六步:Handler执行完成给适配器返回ModelAndView
第七步:处理器适配器向前端控制器返回ModelAndView
第八步:前端控制器请求视图解析器去进行视图解析,通过这种策略很容易更换其他视图技术,只需要更改视图解析器即可
第九步:视图解析器向前端控制器返回View
第十步:前端控制器进行视图渲染
第十一步:前端控制器向用户响应结果
38 Redis持久化RDB的触发方式有哪些?简述RDB的运行流程
触发RDB的方式
符合自定义配置的快照规则
执行save或者bgsave命令
RDB的运行流程
1 执行bgsave命令时,Redis父进程判断当前是否有其他子进程正在执行,如果有其他进程正在执行,直接返回。
2 父进程执行fork操作创建子进程,这个赋值过程中父进程是阻塞的,Redis不能执行来自客户端的任何命令。
3 父进程fork后,bgsave命令返回“Background saving started”信息并不再阻塞父进程,并可以响应其他命令。
4 子进程创建RDB文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行替换
5 子进程发送信号给父进程表示完成,父进程更新统计信息。
39 简述AOF运行流程 AOF重写的流程 AOF保存的模式
AOF执行流程:
1 命令传播:Redis将执行完的命令、命令的参数、命令的参数个数等信息发送到AOF程序中。
2 缓存追加:AOF程序根据接收到的命令数据,将命令转换为网络通讯协议的格式,然后将协议内容追加到服务器的AOF缓存中。
3 文件写入和保存:AOF缓存中的内存被写入到AOF文件末尾,如果设定的AOF保存条件被满足的话,fsync函数或者fdatasync函数会被调用,将文件写入的内容真正的保存到磁盘中
AOF重写流程
手动执行bgrewriteaof函数或者符合redis aof重写规则,主进程使用fork函数创建子进程,将redis内存中的数据重写到新的aof文件中
在aof重写的过程中,如果有新的命令发送到Redis中心,Redis会将新的命令放入到aof缓存区中,满足条件将缓存区的文件写入到aof文件中。
同时新的命令会写入到aof重写缓存区中,在aof重写的时候,会将aof重写缓存区中的内容写到新的aof文件。
当重写完成,用新的aof文件替换原来的aof文件
AOF的保存模式
always(每次)
- 每次写入操作均同步到AOF文件中,数据零误差,性能较低,不建议使用
everysec(每秒) - 每秒将缓存区中的指令同步到AOF文件中,数据准确性较高,性能较高,建议使用,也是默认配置在系统突然宕机的情况下丢失1秒内的数据
no(系统控制) - 有操作系统控制每次同步到AOF文件的调用,整体过程不可控
40 RDB与AOF的对比
rdb是将redis中的数据进行持久化,存储速度比较慢,恢复速度比较快,rdb方式可以保存某一时刻的数据,但是数据会丢失。资源消耗大。
aof 以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中命令达到恢复数据的目的。存储速度比较快,恢复速度比较慢,如果aof的策略是everysec,则每秒将缓冲区的指令同步到AOF文件中,有可能会丢失1s的数据。资源消耗低
41 缓存穿透是什么?解决方案有哪些?缓存雪崩是什么?解决方案有哪些?
缓存穿透
客户端,后台先从缓存中取数据,取到直接返回结果,娶不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果
解决方案
对查询结果为空的情况进行缓存,缓存时间(ttl)设置短一点。
缓存雪崩
缓存雪崩十指缓存中数据大批量到期时间,而查询数据量巨大,引起数据库压力过大甚至down机。
和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到,从而查数据库。
解决方案
缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
如果缓存数据库是分布式集群部署,将热点数据均匀分布在不同的缓存数据库中。
设置热点数据永不过期
缓存击穿
缓存击穿是指缓存中没有用但数据库中有数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没督导数据,又同时去数据库中取数据,引起数据库压力瞬间增大,造成过大压力。
解决方案
设置热点数据永不过期
加互斥锁
42 Redis事务关键字有哪些,作用是什么
Redis的事务是通过multi、exec、discard和watch这四个命令来完成的。Redis事务将命令集合序列化并确保处于同一事务的命令集合连续且不被打断的执行。Redis不支持事务回滚操作。
关键字作用
multi:用于标记事务块的开始,Redis会将后续的命令做个放入队列中,然后使用exec原子化地执行这个命令队列
exec:执行命令队列
discard:清除命令队列
watch:监视key
unwatch:清除监视key
43 Spring中bean的作用域有哪些
- singleton:单例,默认作用域。
- prototype:原型,每次创建一个新对象。
- request:请求,每次Http请求创建一个新对象,适用于WebApplicationContext环境下。
- session:会话,同一个会话共享一个实例,不同会话使用不同的实例。
- global-session:全局会话,所有会话共享一个实例
44 RabbitMQ如何确保消息队列中的消息不丢失
- 生产者开启确认机制,通过setConfirmCallback回调函数,确认信息是否到达交换机。通过setReturnCallback回调函数,确认信息是否到达消息队列,进行后续处理
- 消息存储在RabbitMQ中,为了防止消息丢失,需要将消息进行持久化。
- 消费阶段,将RabbitMQ的确认方式改为手动确认消息。消息方拿到消息以后,正确处理完业务以后,在调用basicAck方法手动确认消息。如果业务处理错误,调用basicNack方法,将消息放回到队列中,重新从队列中获取消息。
45RabbitMQ工作模式有哪些
路由模式
Direct Exchange
要求队列绑定到交换机的时候路由key;消费者发送时需要携带路由key;只有消息的路由key与队列路由key完全一致才能让队列接收消息。
通配符模式
Topic Exchange
要求队列绑定到交换机的时候指定路由key;消费者发送时需要携带路由key;消息的路由key与队列路由key匹配就能让队列接收到消息
发布订阅模式
Fanout Exchange
生产者将消息发给broker,有交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收到消息。
46 谈谈你对Spring的AOP理解
AOP(Aspect-Oriented Programming,面向切面编程)能够将哪些与业务无关,却为业务模块所共同调用的逻辑封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可扩展性和可维护性。
Spring AOP是基于代理的,如果要代理的对象实现了某个接口,那么Spring AOP就会使用JDK动态代理去创建代理对象;而对于没有实现接口的对象,就无法使用JDK动态代理,转而使用CGlib动态代理生成一个被代理对象的子类来作为代理。当然也可以使用AspectJ,Spring AOP中已经继承了AspectJ。
47 SpringAOP与AspectJ的对别
SPring AOP是属于运行时增强,而AspectJ是编译增强。Spring AOP基于代理,而AspectJ基于字节码操作。Spring AOP已经继承了AspectJ,AspectJ相比于Spring AOP功能更加强大,但是Spring AOP相对来说更简单。
如果我们的切面比较少,那么两者性能差异不大,但是,当切面太多的话,最好选择AspectJ,他比Spring AOP快很多。
48 SpringAOP的增强有哪些
before:前值增强,在一个方法执行前被调用。
after:最终增强,在方法执行之后调用的,无论方法是否成功。
after-returning:后置增强,仅当方法成功完成后执行的通知。
after-throwing:异常增强,在方法抛出异常退出时执行的通知。
around:环绕增强,在方法执行之前和之后调用的通知。
49 SpringBean的生命周期
- 实例化Bean
- 对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
- 设置对象属性(依赖注入)
- 实例化后的对象被封装在BeanWrapper对象中,Spring根据BeanDefinition中的信息以及通过Wrapper提供的设置属性的接口完成依赖注入
- 处理Aware接口
- Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean;
- BeanPostProcessir
- 如果相对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPOSTProcessor接口,那将会调用POSTProcessBeforeInitialization(Object obj,String s)方法。
- InitializingBean与 init-method
- 如果Bean在Spring配置文件中配置了init-method属性,则会自动调用其配置的初始化方法。
- 如果这个Bean实现了BeanPostProcessor接口,将会调用POSTProcessAfterInitialization(Object obj,String s)方法:由于这个方法是在Bean初始化结束时调用的,所以可以被应用与内存或缓存技术。
- DisposableBean
- 当Bean不在需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法
- destroy-method
- 最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方。
50 Spring注入bean的几种方式
- Set方法注入
- 构造器注入:通过index设置参数的位置;通过type设置参数的类型;
51 MySQL引擎有哪些
- MYISAM:拥有较高的执行速度,不支持事务,不支持外键,并发性能差,占用空间相对较小,对事务完整性没有要求。
- Innodb:行级锁,提供了具有提交、回滚和崩溃恢复能力的事务安全,支持自动增长列,支持外键约束,并发能力强。
- Memory:存储在内容中,速度快,但会占用和数据量成正比的内存空间且数据在mysql重启时会丢失,默认使用HASH索引,检索效率非常高,但不适用于精确查找,主要用于哪些内容变化不频繁的代码表。
52 ES中的倒排索引原理
每个文档都有一个对应的文档ID,文档内容被差分为一系列关键词的集合。对文档进行分词之后,得到倒排索引。有了倒排索引,搜索引擎可以很方便响应用户的查询。
53 分布式情况下如何保证ID的唯一性
UUID
常见的方式,128位。可以利用数据库也可以利用程序生成,一般来说全球唯一。
优点:
- 简单,代码方便。
- 全球唯一,在遇见数据迁移,系统数据合并,或者数据库变更等情况下,可以从容应对。
缺点
- 没有排序,无法保证趋势递增。
- UUID往往是使用字符串存储,查询的效率比较低。
- 存储空间比较大,如果是海量数据库,就需要考虑储量的问题。
基于Redis INCR命令生成分布式全局唯一ID
采用INCR命令来实现分布式全局ID生成
Twitter的snowflake算法
其核心思想是:使用41bit作为毫秒级时间,10bit作为机器ID,12bit作为1毫秒内的流水号(意味着每个节点在每毫秒可以产生4096个ID),第一个bit位没有使用,永远是0.计算的结果是一个long型的ID。
优点
- 不依赖于数据库,灵活方便,且性能优于数据库。ID按照时间在单机上是递增的。
缺点
- 强依赖机器时钟,如果机器上时间活剥,会导致发号重复或者服务会处于不可用状态。
Seata的处理流程
1 事务管理器向事务协调者申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的事务ID。全局唯一的事务ID在微服务调用链路的上下文中传播。 2 资源管理器向事务协调者注册分支事务,将其纳入全局唯一的事务ID对应全局事务的管辖中。 3 事务管理器向事务协调者发起针对全局唯一事务ID对应的全局事务是进行提交还是回滚决议。 4 事务协调者资源管理器将全局事务ID对应的自己的本地事务进行提交还是回滚。