JAVA面试
2021-09-13 09:56:34 33 举报
AI智能生成
java知识点
作者其他创作
大纲/内容
消息队列
保证消息的顺序性
一个 topic,一个 partition,一个 consumer,内部单线程消费,单线程吞吐量太低,一般不会用这个。
写 N 个内存 queue,具有相同 key 的数据都到同一个内存 queue;然后对于 N 个线程,每个线程分别消费一个内存 queue 即可,这样就能保证顺序性
算法
分治
可以分解为子问题
子问题的解可以合并为原问题的解
子问题之间没有关联
动态规划
按顺序求解子问题
子问题之间有关联关系
最后一个子问题的解为原问题的解
贪心
局部最优解能产生全局最优解
具备后无效性
回溯
深度优先搜索
获取解空间的所有解
分支界定
广度优先搜索
获取解空间的任意解
排序算法
冒泡排序
选择排序
插入排序
快速排序
堆排序
归并排序
计数排序
数据结构
b+树
lsm树
memtable
Sorted String Table
前端
JS的对象属性
__proto__和constructor属性是对象所独有的;prototype属性是函数所独有的。但是由于JS中函数也是一种对象,所以函数也拥有__proto__和constructor属性
__proto__属性的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的__proto__属性所指向的那个对象(父对象)里找,一直找,直到__proto__属性的终点null,再往上找就相当于在null上取值,会报错。通过__proto__属性将对象连接起来的这条链路即我们所谓的原型链
prototype属性的作用就是让该函数所实例化的对象们都可以找到公用的属性和方法,即f1.__proto__ === Foo.prototype
constructor属性的含义就是指向该对象的构造函数,所有函数(此时看成对象了)最终的构造函数都指向Function
高并发
需要运用技术手段抵抗大流量的冲击,能让流量更平稳的被系统所处理,带给用户更好的体验
目标
高性能
体现系统并行处理能力,在有限的硬件投入下,提高性能意味着节省成本
高可用
系统可以正常服务的时间
高扩展
流量高峰时能否在短时间内完成扩容
指标
性能指标
平均响应时间
TP90、TP99等分位值
吞吐量
TPP99应该控制在200毫秒以内,TP999应该控制在1秒以内
可用性指标
SLA
可扩展性指标
扩展性=性能提升比例/机器增加比例,通常维持在70%以上
需要考虑有状态服务的扩展性,数据库、缓存和消息中间件、负载均衡、带宽、依赖的第三方服务都会成为扩展的瓶颈点
方案
纵向扩展
提升单机处理能力
提升单机的硬件性能
提升单机的软件性能
横向扩展
做好分层架构
各层进行水平扩展
高性能
集群部署
多级缓存
分库分表和索引优化
考虑NoSQL数据库的使用
异步化,将次要流程通过多线程、MQ、甚至延时任务进行异步处理
限流,包括前端限流、反向代理层的限流、后端服务限流
对流量进行削峰填谷,通过MQ承接流量
并发处理,通过多线程将串行逻辑并行化
预计算
缓存预热
减少IO次数,数据库和缓存的批量读写,批量接口的支持
减少IO时的数据包大小,减少接口的多余字段、减少缓存key的大小
程序逻辑优化
各种池化技术的使用和大小设置,包括线程池、连接池
JVM优化,减少GC频率和耗时
锁选择
高可用
对等节点的故障转移
非对等节点的故障转移
接口层面的超时设置、重试策略和幂等设计
降级处理,保证核心业务,牺牲非核心业务
限流处理
MQ消息的可靠性保证,producer端的重试机制,broker的持久化,consumer端的ACK机制
灰度发布
监控告警
灾备演练
高扩展
合理的分层架构
存储层的拆分
业务层的拆分
linux参数优化
vmstat分析
procs(进程)
r:表示运行队列中进程的数量,就是有多少个进程真的分配到cpu,当这个值超过了cpu数目,就会出现cpu瓶颈了。
b:等待IO的进程数量,即阻塞的进程数。
memory(内存)
swpd: 表示虚拟内存的已使用的大小,如果大于0,表示物理内存不足了,如果不是程序内存泄漏的原因,该升级内存了。
free:空闲的物理内存大小。
buff:用作缓冲的内存大小。
cache:用作缓存的内存大小。
swap(交换区)
Si:每秒从磁盘读入虚拟内存的大小,如果这个值大于 0,表示物理内存不够用或者内存泄露了,要查找消耗内存进程解决掉。
So:每秒虚拟内存写入磁盘的大小
IO
bi:每秒读取的的块数。
bo:每秒写入的块数。
如果bi和bo经常不等于0,表示内存不足。
system(系统)
in:每秒 cpu 的中断次数,包括时间中断。
cs:每秒上下文切换次数
CPU(百分比表示)
us:用户进程占用cpu时间百分比
sy:系统进程占用cpu时间百分比,如果太高,表示系统调用时间长,例如IO操作频繁。
id:空闲cpu时间百分比,如果r经常大于4,并且id经常少于40,表示cpu的负载很重。
wa:IO等待时间百分比,过高时,说明io等待比较严重,可能是由于磁盘大量随机访问造成的,也有可能是磁盘的带宽出现瓶颈。
r:表示运行队列中进程的数量,就是有多少个进程真的分配到cpu,当这个值超过了cpu数目,就会出现cpu瓶颈了。
b:等待IO的进程数量,即阻塞的进程数。
memory(内存)
swpd: 表示虚拟内存的已使用的大小,如果大于0,表示物理内存不足了,如果不是程序内存泄漏的原因,该升级内存了。
free:空闲的物理内存大小。
buff:用作缓冲的内存大小。
cache:用作缓存的内存大小。
swap(交换区)
Si:每秒从磁盘读入虚拟内存的大小,如果这个值大于 0,表示物理内存不够用或者内存泄露了,要查找消耗内存进程解决掉。
So:每秒虚拟内存写入磁盘的大小
IO
bi:每秒读取的的块数。
bo:每秒写入的块数。
如果bi和bo经常不等于0,表示内存不足。
system(系统)
in:每秒 cpu 的中断次数,包括时间中断。
cs:每秒上下文切换次数
CPU(百分比表示)
us:用户进程占用cpu时间百分比
sy:系统进程占用cpu时间百分比,如果太高,表示系统调用时间长,例如IO操作频繁。
id:空闲cpu时间百分比,如果r经常大于4,并且id经常少于40,表示cpu的负载很重。
wa:IO等待时间百分比,过高时,说明io等待比较严重,可能是由于磁盘大量随机访问造成的,也有可能是磁盘的带宽出现瓶颈。
iostat分析
%user:用户层面使用CPU的情况。
%system:系统层面使用CPU的情况,如果该值较高,多半是IO出了问题。因为MySQL的IO请求发出后,最终是由系统的IO进程完成,假如读写很高的话,sys就很繁忙。
%iowait:IO等待情况,iowait 很高的话表示浪费cpu资源。
%idle:cpu 空闲时间。
system和iowait一般结合着看,表示系统IO的情况,如果iowait很高的话,说明cpu花太多的时间在IO等待上,说明系统的IO成为瓶颈了,iowait一般希望小于5%,如果大于25%就说明有问题了。Idle一般希望大于25%,希望有25%的时间是空闲的。
关于Device一栏,描述了IO的具体使用情况。
rrqm/s:合并读,合并读一般为0,如果值很高的话,说明系统有大量的全表扫描。因为
数据库的特点是随机读(oltp交易系统),所以两个读被合并的概率很低,所以如果出现大量的合并读,说明系统在全盘扫描。
wrqm/s:合并写,如果系统在做批量的insert,并且是按照主键顺序递增插入的时候,该值会比较高。
r/s:每秒读。
w/s:每秒写。每秒读+每秒写=IOPS,可以看出系统是读还是写为主。
rsec/s:每秒读扇区的数量。每个扇区是 512 字节。
wsec/s:每秒写扇区的数量。rsec/s+ wsec/s就是IO的吞吐量。
avgrq-sz:平均每次IO操作的扇区数。
avgqu-sz:平均等待处理的IO请求队列长度
await:平均每次IO请求的等待时间。
svctm:每一个请求的服务时间(单位毫秒),反应了io性能,5、6ms表示io性能还可以,可以降到1ms以下。
%util:繁忙度,周期内用于IO操作的时间比例,即IO队列非空的时间比率。如果io不高,但繁忙度高,说明磁盘有问题
%system:系统层面使用CPU的情况,如果该值较高,多半是IO出了问题。因为MySQL的IO请求发出后,最终是由系统的IO进程完成,假如读写很高的话,sys就很繁忙。
%iowait:IO等待情况,iowait 很高的话表示浪费cpu资源。
%idle:cpu 空闲时间。
system和iowait一般结合着看,表示系统IO的情况,如果iowait很高的话,说明cpu花太多的时间在IO等待上,说明系统的IO成为瓶颈了,iowait一般希望小于5%,如果大于25%就说明有问题了。Idle一般希望大于25%,希望有25%的时间是空闲的。
关于Device一栏,描述了IO的具体使用情况。
rrqm/s:合并读,合并读一般为0,如果值很高的话,说明系统有大量的全表扫描。因为
数据库的特点是随机读(oltp交易系统),所以两个读被合并的概率很低,所以如果出现大量的合并读,说明系统在全盘扫描。
wrqm/s:合并写,如果系统在做批量的insert,并且是按照主键顺序递增插入的时候,该值会比较高。
r/s:每秒读。
w/s:每秒写。每秒读+每秒写=IOPS,可以看出系统是读还是写为主。
rsec/s:每秒读扇区的数量。每个扇区是 512 字节。
wsec/s:每秒写扇区的数量。rsec/s+ wsec/s就是IO的吞吐量。
avgrq-sz:平均每次IO操作的扇区数。
avgqu-sz:平均等待处理的IO请求队列长度
await:平均每次IO请求的等待时间。
svctm:每一个请求的服务时间(单位毫秒),反应了io性能,5、6ms表示io性能还可以,可以降到1ms以下。
%util:繁忙度,周期内用于IO操作的时间比例,即IO队列非空的时间比率。如果io不高,但繁忙度高,说明磁盘有问题
调整swap
vi /etc/sysctl.conf
加入vm.swappiness = 10
#执行下面命令生效
sysctl -p /etc/sysctl.conf
加入vm.swappiness = 10
#执行下面命令生效
sysctl -p /etc/sysctl.conf
调整文件句柄
vi /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535
调整tcp连接
vim /etc/sysctl.conf
net.ipv4.tcp_syncookies= 1#表示开启SYNCookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN***,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse= 1#表示开启重用。允许将TIME-WAITsockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle= 1#表示开启TCP连接中TIME-WAITsockets的快速回收,默认为0,表示关闭;
net.ipv4.tcp_fin_timeout#修改系統默认的TIMEOUT 时间。
net.ipv4.tcp_keepalive_time= 1200#表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。
net.ipv4.ip_local_port_range= 1024 65535#表示用于向外连接的端口范围。缺省情况下很小,改为1024到65535。
net.ipv4.tcp_max_syn_backlog= 8192#表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_max_tw_buckets= 5000#表示系统同时保持TIME_WAIT的最大数量,如果超过这个数字,TIME_WAIT将立刻被清除并打印警告信息。默认为180000,改为5000。此项参数可以控制TIME_WAIT的最大数量,只要超出了。
net.ipv4.tcp_max_syn_backlog= 65536#记录的那些尚未收到客户端确认信息的连接请求的最大值。对于有128M内存的系统而言,缺省值是1024,小内存的系统则是128。
net.core.netdev_max_backlog= 32768#每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。
net.core.somaxconn= 32768#例如web应用中listen函数的backlog默认会给我们内核参数的net.core.somaxconn限制到128,而nginx定义的NGX_LISTEN_BACKLOG默认为511,所以有必要调整这个值。
net.ipv4.tcp_tw_reuse= 1#表示开启重用。允许将TIME-WAITsockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle= 1#表示开启TCP连接中TIME-WAITsockets的快速回收,默认为0,表示关闭;
net.ipv4.tcp_fin_timeout#修改系統默认的TIMEOUT 时间。
net.ipv4.tcp_keepalive_time= 1200#表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。
net.ipv4.ip_local_port_range= 1024 65535#表示用于向外连接的端口范围。缺省情况下很小,改为1024到65535。
net.ipv4.tcp_max_syn_backlog= 8192#表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_max_tw_buckets= 5000#表示系统同时保持TIME_WAIT的最大数量,如果超过这个数字,TIME_WAIT将立刻被清除并打印警告信息。默认为180000,改为5000。此项参数可以控制TIME_WAIT的最大数量,只要超出了。
net.ipv4.tcp_max_syn_backlog= 65536#记录的那些尚未收到客户端确认信息的连接请求的最大值。对于有128M内存的系统而言,缺省值是1024,小内存的系统则是128。
net.core.netdev_max_backlog= 32768#每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。
net.core.somaxconn= 32768#例如web应用中listen函数的backlog默认会给我们内核参数的net.core.somaxconn限制到128,而nginx定义的NGX_LISTEN_BACKLOG默认为511,所以有必要调整这个值。
java基础
多线程
同步与互斥
Synchronized
同步方法,字节码中添加ACC_SYNCHRONIZED flags,线程需要先获取对象的monitor对象
同步代码块,会遇到monitorenter和monitorexit指令,而该指令依赖monitor对象完成
锁升级
无锁
偏向锁
轻量锁
自旋锁
monitor
Contention List:竞争队列,所有请求锁的线程首先被放在这个竞争队列中;
Entry List:Contention List 中那些有资格成为候选资源的线程被移动到 Entry List 中;
OnDeck:任意时刻,最多只有一个线程正在竞争锁资源,该线程被成为 OnDeck;
Owner:当前已经获取到所资源的线程被称为Owner;
Wait Set:哪些调用 wait 方法被阻塞的线程被放置在这里
Lock
基于wait和notify实现
CAS
基于unsafe类的compareAndSwap实现
AQS
state
CLH队列
类似zookeeper的分布式锁
独占锁与共享锁
volatile
保证内存可见性
防止指令重排
ThreadLocal
基于ThreadLocalMap,每个线程拥有独立的map,key为ThreadLocal
InheritableThreadLocal
用于父线程传递ThreadLoca的值到子线程
子线程在init方法里判断父线程是否使用了InheritableThreadLocal,有则copy一份值到本线程内
子线程如果使用线程池,由于线程池的线程可能已经创建无法重新调用init方法,会导致值无法正常传递,可以使用阿里的方案TransmittableThreadLocal
LockSupport
基于unsafe类的park和unpark实现
常用工具类
ConcurrentXXX
AtomicXXX
XXXAccumulator
Queue
Locks
Caller、Future
CountDownLatch、CyclicBarrier、Semaphone
线程通信
wait
notify
notifyAll
线程状态
new
ready
running
blocked
waiting
timewaiting
terminated
线程池
fixed固定线程数
cache无限线程数
single单个线程
schedule定时线程
workstealing多任务队列的固定并行度
实现原理
判断条件,核心线程数是否已满、队列是否已满、是否达到最大线程数
生成Worker对象,将任务设置为firstTask,执行worker对象的线程启动方法,先执行firstTask
执行完firstTask,然后从工作队列里不断取出任务执行,线程存活时间也是基于队列取数据的超时时间的设置来控制的
扩展知识点
守护线程
没有用户线程可服务时会自动离开
指令重排
编译器优化的重排序
指令级并行的重排序
内存系统的重排序
as-if-serial
编译器和处理器不会对存在数据依赖关系的操作做重排序。但是as-if-serial规则允许对有控制依赖关系的指令做重排序
进程和线程区别
线程是程序执行的最小单位,进程是操作系统分配资源的最小单位
一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线
进程之间相互独立,但同一进程下的各个线程之间共享内存空间以及一些进程级的资源
线程上下文切换比进程上下文切换快的多,主要是进程切换涉及虚拟地址空间的切换,页表切换会引起TLB缓存失效,进而引起程序运行变慢
线程用户态切换到内核态切换
切换途径 1:系统调用 2:中断 3:异常
切换流程
读取tr寄存器,访问TSS段
从TSS段中的esp0获取进程内核栈的栈顶指针
由控制单元在内核栈中保存当前eflags,cs,ss,eip,esp寄存器的值。
由SAVE_ALL保存其寄存器的值到内核栈
把内核代码选择符写入CS寄存器,内核栈指针写入ESP(栈顶指针)寄存器,把内核入口点的线性地址写入EIP寄存器
此时,CPU已经切换到内核态,根据EIP(存储CPU下次所执行的指令地址)中的值开始执行内核入口点的第一条指令
IO多路复用
select
创建
fd_set rset , allset;
FD_ZERO(allset);
FD_SET(listenfd, allset);
FD_ZERO(allset);
FD_SET(listenfd, allset);
监听
nready = select(maxfd+1 , rset , NULL , NULL , NULL);
select最大的缺陷就是单个进程所打开的FD是有一定限制的,它由FD_SETSIZE设置,默认值是1024
将要监听的FD放入rset的数组中,有事件来的时候,需要遍历rset数组,判断有没有需要处理的事件
需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大
将要监听的FD放入rset的数组中,有事件来的时候,需要遍历rset数组,判断有没有需要处理的事件
需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大
poll
创建
struct pollfd client[OPEN_MAX];
client[0].fd = listenfd;
client[0].events = POLLRDNORM;
监听
nready = poll(client,maxi+1,INFTIM);
poll基于链表存储FD,所以没有最大数限制
使用pollfd结构体数组,有事件来的时候,遍历pollfd结构体数组,判断结构体的reevents是否需要处理
每当调用poll函数之后,系统不会清空这个数组,select()函数会清空它所检测的socket描述符集合
poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd
使用pollfd结构体数组,有事件来的时候,遍历pollfd结构体数组,判断结构体的reevents是否需要处理
每当调用poll函数之后,系统不会清空这个数组,select()函数会清空它所检测的socket描述符集合
poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd
epoll
创建
int epfd;
struct epoll_event ev, events[20];
epfd = epoll_create(256);
ev.data.fd=listenfd;
ev.events=EPOLLIN|EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,ev);
struct epoll_event ev, events[20];
epfd = epoll_create(256);
ev.data.fd=listenfd;
ev.events=EPOLLIN|EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,ev);
监听
nfds=epoll_wait(epfd,events,20,500);
epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次
epoll支持水平触发和边缘触发,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就绪态,并且只会通知一次
使用epoll_event结构体,有事件来的时候,直接遍历events,判断有没有需要处理的事件
epoll支持水平触发和边缘触发,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就绪态,并且只会通知一次
使用epoll_event结构体,有事件来的时候,直接遍历events,判断有没有需要处理的事件
JVM
内存模型
线程私有
栈
局部变量表
操作数栈
动态链接,运行期间符号引用转换为直接引用
方法出口
本地方法栈
程序计数器
线程共享
堆
方法区
运行时常量池
字面量
符号引用
类信息
常量
静态变量
即时编译后的代码
类的加载
加载
全限定名称获取二进制字节流
所代表的静态存储结构转化为方法区的运行时数据结构
堆中生成代表类的class对象,作为方法区的数据入口
验证
文件格式
元数据
是否有父类
是否不可继承
类中的字段、方法是否与父类产生冲突
字节码
指令转换
类型转换
符号引用
全限定名找到对应的类
准备
类变量分配内存
解析
引用替换
字段解析
方法解析
接口解析
初始化
静态变量
静态代码块
主动引用
创建类的实例
调用类的静态变量和静态方法
通过反射对类进行调用
初始化某个类的子类,父类也会被初始化
虚拟机启动指定main方法的类
被动引用,不会触发类的初始化
访问类的静态变量为父类所持有
通过数据定义引用类,例如初始化一个数据类型的数组
引用类的常量
加载器
BootStrap ClassLoader
ExtClassLoader
AppClassLoader
Custorm ClassLoader
垃圾收集器
CMS
初始标记(STW)
并发标记
重新标记(STW)
并发清理
并发重置
G1
年轻代回收
并行复制(STW)
老年代回收
初始标记(STW)
并发标记
最终标记(STW)
复制/清除(STW)
ZGC
着色指针
读屏障
并发处理
基于Region
内存压缩
编译
逃逸分析
对象被赋值给堆中对象的字段和类的静态变量
对象被传进了不确定的代码中运行
优化
将堆分配转化为栈分配
同步锁消除
分离对象或标量替换
前端编译
解析与填充符号表,词法分析和语法分析
插入式注解处理器,看作是一组编译器插件
语义分析与字节码生成
后端编译
C1编译,将字节码编译为本地代码,进行简单可靠的优化
C2编译,启用一些编译耗时较长的优化
对象头
Mark Word
32位4个字节,64位8个字节
class pointer
32位4个字节;64位8个字节,开启指针压缩为4个字节
array length
数组对象时才有,4个字节
安全点
场景
GC时为了避免对象被误回收。分配一个对象时,地址还在寄存器中,这时候这个线程失去了CPU 时间片,GC发现没有任何GC ROOTS与该对象关联起来,此时这个对象呗认为是垃圾并被回收
安全点
循环的末尾
方法返回前
调用方法的call之后
抛出异常的位置
安全区域
是指一段代码片中,引用关系不会发生变化,在这个区域任何地方GC都是安全的
中断
主动式中断(jvm采用方案):在 GC 发生时,不直接操作线程中断,而是简单地设置一个标志,让各个线程执行时主动轮询这个标志,发现中断标志为真时就自己中断挂起。
抢断式中断:在 GC 发生时,首先中断所有线程,如果发现线程未执行到 Safe Point,就恢复线程让其运行到 Safe Point 上。
集合框架
HashMap
数组长度使用2的幂次方,因为取模的算法采用 长度-1&hashcode
hashcode使用高16位与低16位取异或避免hash碰撞
1.7
数组+链表
扩容使用头插法,并发时可能引起死循环
1.8
数组+红黑树
扩容时,使用与原数组长度取与,通过高位值判断是否需要变换索引位置
key和value可以为null,key为null的位置在数组第0位
ConcurrentHashMap
1.7
使用segment分段锁同步,默认使用16个segment
1.8
只对每个数组的索引进行加锁操作
在一个线程发起扩容的时候,就会改变sizeCtl这个值
-1 代表table正在初始化
-N 表示有N-1个线程正在进行扩容操作
如果table未初始化,表示table需要初始化的大小。
如果table初始化完成,表示table的容量,默认是table大小的0.75倍
其他线程的有写操作都会判断head节点是否为forwardNode(hash值返回MOVED[-1])节点,如果是就帮助扩容
key,value不能为null
TreeMap
使用红黑树实现排序
ArrayList
扩容使用1.5倍长度扩容
CopyOnWriteArrayList
写操作加锁,copy一份数据进行操作,操作完以后替换原数据
LinkedList
线上问题排查
jstack查询线程运行代码和锁的情况
jinfo查看和修改jvm参数
jmap查看内存使用情况
jhat分析内存dump文件
jstat统计监测jvm
spring
核心类
DefaultListableBeanFactory
ConfigurableBeanFactory提供配置Factory的各种方法
ListableBeanFactory获取bean的配置清单
BeanDefinition
手动注册BeanDefinition
实现ImportBeanDefinitionRegistrar
实现BeanDefinitionRegistryPostProcessor
BeanDefinitionRegistry
BeanWrapper
对Bean的一种包装,动态获取和设置属性值
FactoryBean
bean生命周期
构造函数
依赖注入
BeanNameAware
BeanFactoryAware
ApplicationContextAware
BeanPostProcessor前置方法
InitializingBean
自定义init方法
BeanPostProcessor后置方法
DisposableBean
自定义destroy方法
扩展接口
BeanFactoryPostProcessor
处理所有bean前,对bean factory进行预处理
BeanDefinitionRegistryPostProcessor
可以添加自定义的bean
BeanPostProcessor
支持在bean初始化前、后对bean进行处理
InitalizingBean
bean创建完成,所有属性注入完成后执行
ApplicationListener
用来监听产生的应用事件
springboot
通过maven插件将依赖包也打进最终的Jar,变成一个可运行的FatJar
MANIFEST.MF文件中Main-Class是JarLauncher,Start-Class才是自定义应用的主类
LaunchedURLClassLoader自定义类加载器,支持识别多个!/分隔符
Servlet3.0
扫描jar包的META-INF/services/javax.servlet.ServletContainerInitializer
SPI机制加载SpringServletContainerInitializer
HandlesTypes注解可以将WebApplicationInitializer接口的实现类作为ServletContainerInitializer的onStartup方法的第一个入参里面
SpringBootServletInitializer实现了WebApplicationInitializer
war包部署时需继承SpringBootServletInitializer,实现configure方法
CommandLineRunner、ApplicationRunner 接口是在容器启动成功后的最后一步回调
SpringApplicationRunListener接口回调来让用户在启动的各个流程中可以加入自己的逻辑
开始启动
Environment构建完成
ApplicationContext构建完成
ApplicationContext完成加载
ApplicationContext完成刷新并启动
启动完成
启动失败
springmvc
流程
DispatcherServlet收到请求调用处理器映射器HandlerMapping。
处理器映射器HandlerMapping根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
执行处理器Handler(Controller,也叫页面控制器)。
Handler执行完成返回ModelAndView
HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
DispatcherServlet将ModelAndView传给ViewReslover视图解析器
ViewReslover解析后返回具体View
DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
组件
HandlerMapping
处理器映射器默认:BeanNameUrlHandlerMapping
HandlerAdapter
处理器适配器默认:HttpRequestHandlerAdapter
ViewResolver
视图解析器默认:InternalResourceViewResolver
webflux
异步非阻塞的web框架
适用于IO密集型的服务
一个线程可以处理更多的请求,springmvc一个请求会对应容器的一个线程
bean缓存
singletonObjects
存放初始化好的bean
earlySingletonObjects
存放了刚实例化好的,但是还未配置属性和初始化的bean
singletonFactories
存放我刚实例化的bean,通过ObjectFactory获取bean
mybatis
主要对象
SqlSessionFactory
SqlSession
Executor
SimpleExecutor:每执行一次 update 或 select,就开启一个 Statement 对象,用完立刻关闭 Statement 对象
ReuseExecutor:执行 update 或 select,以 sql 作为key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,而是放置于 Map
BatchExecutor:完成批处理
StatementHandler
ParameterHandler
ResultSetHandler
TypeHandler
完成从 javaType 至 jdbcType 的转换
完成 jdbcType 至 javaType 的转换
setParameter()和 getResult()两个方法,分别代表设置 sql 问号占位符参数和获取列查询结果
插件机制
拦截器实现
实现Interceptor 接口
使用@Intercepts注解完成插件签名,注解里描述指定拦截方法的签名 [type,method,args]
拦截器拦截接口
Executor
StatementHandler
ParameterHandler
ResultSetHandler
缓存
一级缓存
作用域是session
HashMap实现
默认开启
二级缓存
作用域是Mapper(namespace)
支持ehcache等缓存实现
可配置删除策略、刷新间隔、缓存数量等
mapper接口里的方法不能重载
缓存
缓存不一致
同步更新失败、异步更新
增加重试、补偿任务、最终一致
缓存穿透
恶意攻击
空对象缓存、布隆过滤器
缓存击穿
热点key失效
互斥更新、随机退避、差异失效时间
缓存雪崩
缓存挂掉
快速失败熔断、主从模式、集群模式
缓存淘汰策略
LRU
利用双向链表和哈希表存储,借助哈希表快速查询数据,再利用链表快速插入头部和删除
LFU
同样利用哈希表和双向链表存储,利用一个哈希表以频次为key存储链表数据,来实现使用频率的链表存储
函数式编程
特性
不可变数据、无副作用、引用透明
高阶函数
函数作为入参或返回值的函数
惰性求值
减少不必要的计算
柯里化
接受多个参数的函数转换成接受一个单一参数,并且返回接受余下参数的函数,参数可以复用,延迟运行
闭包
定义在一个函数内部的函数,外部函数调用内部函数的时候,内部函数叫做闭包
读取函数内部的变量、让变量始终保存在内存中
设计
设计模式
单例
懒汉式
饿汉式
工厂
spring创建bean
简单工厂
抽象工厂
建造者
原型
对象克隆
适配器
slfj日志框架
类适配器
对象适配器
接口适配器
装饰器
实现接口,传入实例对象,接口方法前后调用改造
代理
spring aop
享元
连接池
策略
观察者
spring event
责任链
filter过滤器
模板方法
solid设计原则
单一职责
开放封闭
里氏替换
接口隔离
依赖倒置
发布策略
蓝绿发布
新旧版本并存,新旧版本相互热备,通过切换路由权重方式(非0即100)实现不同应用的上线或下线,缺点是资源消耗大
金丝雀发布
切换并存版本间的路由权重,倾向于获取快速的反馈,根据反馈决定最后的交付形态,主要用于功能兼容的新版本验证
灰度发布
类似金丝雀发布,倾向于从一个版本到另一个版本长时间平稳的切换
A/B测试
侧重从A、B版本之间的差异,根据结果进行决策
流量分流策略
基于header
基于cookie
基于query参数
基于服务权重
觉得不错,帮忙点个赞
赠人玫瑰,手留余香
赠人玫瑰,手留余香
0 条评论
下一页