一面(电话面,大概20多分钟都是问基础)
1.mysql索引原理 从B树说到B+树
- B+树所有的data的叶子节点,其余用于存放索引(b树每个索引节点都用data)==》可以放更多的索引
- B+树所有的叶子节点之间都有链指针,比那与分区查找;范围查找
- hash 只能等值查找,不支持条件模糊查找,还有碰撞
- 红黑树,不是自平衡;逻辑很近物理远,局部性原理无法用到
2.快速排序时间复杂度,最好最坏, 为什么 最坏O(n^2)? 希尔排序是稳定的吗?(不稳定)(简历里写了熟悉排序算法)
3.责任链模式
4.filter过滤器与Spring拦截器区别
5. 线程池饱和策略
6.Redis的zset底层原理
1. 编码
zset的编码有ziplist和skiplist两种。
底层分别使用ziplist(压缩链表)和skiplist(跳表)实现。
什么时候使用ziplist什么时候使用skiplist?
当zset满足以下两个条件的时候,使用ziplist:
保存的元素少于128个
保存的所有元素大小都小于64字节
不满足这两个条件则使用skiplist。
(注意:这两个数值是可以通过redis.conf的zset-max-ziplist-entries 和 zset-max-ziplist-value选项 进行修改。)
每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个节点保存元素的分值。并且压缩列表内的集合元素按分值从小到大的顺序进行排列,小的放置在靠近表头的位置,大的放置在靠近表尾的位置。
一个 zset 结构同时包含一个字典和一个跳表:
typedef struct zset{
//跳跃表
zskiplist *zsl;
//字典
dict *dice;
} zset;
字典的键保存元素的值,
字典的值则保存元素的分值
这两种数据结构会通过指针来共享相同元素的成员和分值,所以不会产生重复成员和分值,造成内存的浪费。
7.新生代为什么要分Eden空间 Survivor空间
介绍:新生代会被分为一块较大Eden空间和两块较小的Survivor空间(分别称为from和to),默认大小比例为8:1:1
解答:新生代在垃圾收集时采用的是标记-复制算法,每次分配内存的时候只分配其中的eden区和其中一块Survivor区。发生垃圾收集的时候,只收集使用过的eden区和使用过的Survivor区,把存活下来的对象一次性复制到另一块Survivor上,再清理掉eden区和使用过的Survivor区。
产生的问题:虽然每次新生代收集(Minor GC)都能达到98%的回收率,但是也会出现Survivor区放不下存活的对象。这时就需要依赖其他内存区域进行内存担保,如果Survivor区不够存放上一次新生代收集下来的存活对象,这么对象将通过内存担保机制直接进入老年代。
二面(电话面50分钟,针对项目来问)
1.http是无状态的,怎么知道是那个用户访问
- cookie+session
(1)当有Session启动时,服务器生成一个唯一值,称为Session ID(好像是通过取进程ID的方式取得的)。
(2)然后,服务器开辟一块内存,对应于该Session ID。
(3)服务器再将该Session ID写入浏览器的cookie。
(4)服务器内有一进程,监视所有Session的活动状况,如果有Session超时或是主动关闭,服务器就释放改内存块。
(5)当浏览器连入IIS时并请求的ASP内用到Session时,IIS就读浏览器Cookie中的Session ID。
(6)然后,服务检查该Session ID所对应的内存是否有效。
(7)如果有效,就读出内存中的值。
(8)如果无效,就建立新的Session。
- 共享session: token+redis:登录成功将登录信息放入redis里面,然后服务器从数据库里面查询;使用第三方客户端redis
2.登陆部分怎么设计的, Cookie有什么缺点
1.数据持久性
2.不需要任何服务器资源。Cookie 存储在客户端并在发送后由服务器读取。
3.可配置到期规则。 控制 cookie 的生命期,使之不会永远有效。偷盗者很可能拿到一个过期的 cookie 。
4.简单性。 基于文本的轻量结构。
缺点:
1.`Cookie`数量和长度的限制。
数量:每个domain的 cookie 总数有限。
a.IE6 或更低版本最多 20 个 cookie
b.IE7 和之后的版本最后可以有 50 个 cookie
c.Firefox 最多 50 个 cookie
d.chrome 和 Safari 没有做硬性限制
长度:每个 cookie 长度不超过 4KB ( 4096B ),否则会被截掉。
2.潜在的安全风险 。Cookie 可能被拦截、篡改。如果 cookie 被拦截,就有可能取得所有的 session 信息。
5.cookie在每次发送http请求时,都会被发送到服务器,一些不必要的信息也会被发送过去,造成不必要的浪费
3.跨域问题,(使用jsonp ),jsonp怎么实现的
- 修改浏览器的设置
- 修改请求的方式:jsonp
- CORS
- 服务器反向代理
反向代理是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
首先是利用script标签的src属性来实现跨域。
通过将前端方法作为参数传递到服务器端,然后由服务器端注入参数之后再返回,实现服务器端向客户端通信。
由于使用script标签的src属性,因此只支持get方法
4.ThreadLocal原理
5.项目里的异步消息队列怎么做的
6. 异步消息队列怎么进一步优化(面试官其实是想要我从IO方面考虑,但是我当时没想到)
7.BIO、NIO(问的很细,包括底层有几条线程,怎么工作)
8.使用NIO代码怎么写(NIO真的没怎么用过)
9.springAOP原理
Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,
那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,
就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,
这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理,如下图所示:
10.CGLIB与JDK动态代理的区别
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
如何强制使用CGLIB实现AOP?
(1)添加CGLIB库,SPRING_HOME/cglib/*.jar
(2)在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
JDK动态代理和CGLIB字节码生成的区别?
(1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类
(2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法因为是继承,所以该类或方法最好不要声明成final
11.JDK动态代理为什么要提供接口(我说用接口可以针对抽象层编程。。。,然后面试官告诉了我正确答案)
JDK的动态代理是靠多态和反射来实现的,它生成的代理类需要实现你传入的接口,并通过反射来得到接口的方法对象(下文中的m3),并将此方法对象传参给增强类(上文中的WavingInvocationHandler类)的invoke方法去执行,从而实现了代理功能,故接口是jdk动态代理的核心实现方式,没有它就无法通过反射找到方法,所以这也是必须有接口的原因。不知道大家明白否
extends Proxy
生成的代理类由于其规则要继承proxy,由于单继承限制,所以目标类只能和代理类实现相同的接口,来达到兄弟的关系。而cglib是生成子类,二者是父子关系