Java 八股文

《 脏读、幻读和不可重复读》
六、Spring 相关
1、Bean 的作用域
|:---|:---| | 类别 | 说明 | |singleton| 默认在 Spring 容器中仅存在一个实例 | |prototype| 每次调用 getBean() 都重新生成一个实例 | |request| 为每个 HTTP 请求生成一个实例 | |session| 同一个 HTTP session 使用一个实例,不同 session 使用不同实例 |
2、Bean 生命周期
简单来说四步:
- 实例化 Instantiation
- 属性赋值 Populate
- 初始化 Initialization
- 销毁 Destruction
在这四步的基础上面,Spring 提供了一些拓展点:
- Bean 自身的方法: 这个包括了 Bean 本身调用的方法和通过配置文件中 %3Cbean %3E 的 init-method 和 destroy-method 指定的方法
- Bean 级生命周期接口方法: 这个包括了 BeanNameAware、BeanFactoryAware、InitializingBean 和 DiposableBean 这些接口的方法
- 容器级生命周期接口方法:这个包括了 InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。
- 工厂后处理器接口方法: 这个包括了 AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer 等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。
3、Spring AOP
实现方式两种:
- JDK 动态代理:带有接口的对象,在运行期实现
- CGlib 静态代理:在编译期实现。
4、Spring 事务传播行为
默认 PROPAGATION_REQUIRED ,如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。

5、Spring IoC

6、Spring MVC 工作流程

七、计算机网络
1、TCP/IP 五层模型

2、浏览器输入地址后做了什么?

3、三次握手与四次挥手
- 三次握手

- 四次挥手

4、TIME_WAIT 与 CLOSE_WAIT

5、TCP 滑动窗口
TCP 流量控制,主要使用滑动窗口协议,滑动窗口是接受数据端使用的窗口大小,用来告诉发送端接收端的缓存大小,以此可以控制发送端发送数据的大小,从而达到流量控制的目的。这个窗口大小就是我们一次传输几个数据。对所有数据帧按顺序赋予编号,发送方在发送过程中始终保持着一个发送窗口,只有落在发送窗口内的帧才允许被发送;同时接收方也维持着一个接收窗口,只有落在接收窗口内的帧才允许接收。
6、TCP 粘包和拆包
- 现象

- 产生原因 1、要发送的数据大于 TCP 发送缓冲区剩余空间大小,将会发生拆包。 2、待发送数据大于 MSS(最大报文长度),TCP 在传输前将进行拆包。 3、要发送的数据小于 TCP 发送缓冲区的大小,TCP 将多次写入缓冲区的数据一次发送出去,将会发生粘包。 4、接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。
- 解决方式 1、发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。 2、发送端将每个数据包封装为固定长度(不够的可以通过补 0 填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。 3、可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。
八、MQ 消息队列
1、场景作用
削峰填谷,异步解耦。
2、如何保证消息不被重复消费呢?
这个问题可以换个思路,保证消息重复消费,其实是保证程序的幂等性。无论消息如何重复,程序运行的结果是一致的。比如消费消息后做数据库插入操作,为了防止消息重复消费,可以在插入前先查询一下有没有对应的数据。
3、怎么保证从消息队列里拿到的数据按顺序执行?
消费端在接收到消息后放入内存队列,然后对队列中的消息进行有序消费。
4、如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?
消息过期失效问题,如果消息一段时间不消费,导致过期失效了,消息就丢失了,只能重新查出丢失的消息,重新发送。 再来说消息积压的问题:(思路是快速消费掉积压的消息)
- 首先排查消费端问题,恢复消费端正常消费速度。
- 然后着手处理队列中的积压消息。
- 停掉现有的 consumer。
- 新建一个 topic ,设置之前 10 倍的 partation,之前 10 倍的队列。
- 写一个分发程序,将积压的消息均匀的轮询写入这些队列。
- 然后临时用 10 倍的机器部署 consumer,每一批 consumer 消费 1 个临时的队列。
- 消费完毕后,恢复原有架构。
消息队列满了:只能边接收边丢弃,然后重新补回丢失的消息,再做消费。
4、如何保证消息的可靠性传输(如何处理消息丢失的问题)?
kafka 为例:
- 消费者丢了数据: 每次消息消费后,由自动提交 offset 改为手动提交 offset 。
- kafka 丢了消息: 比较常见的一个场景,就是 kafka 某个 broker 宕机,然后重新选举 partition 的 leader 时。要是此时其他的 follower 刚好还有些数据没有同步,结果此时 leader 挂了,然后大家选举某个 follower 成为 leader 之后,不就少了一些数据。
- 给 topic 设置replication.factor参数:这个值必须大于 1,要求每个 partition 必须有至少两个副本。
- 在 kafka 服务端设置min.insync.replicas参数:这个值必须大于 1,这个是要求一个 leader 至少感知到有至少一个 follower 还跟自己保持联系,没掉队,这样才能确保 leader 挂了还有一个 follower。
- 在 producer 端设置acks=all:这个是要求每条数据,必须是写入所有 replica 之后,才能认为是写成功了。
- 在 producer 端设置retries=MAX(很大很大很大的一个值,无限次重试的意思):这个是要求一旦写入失败,就无限重试,卡在这里。
- 生产者丢了消息: 如果按照上述的思路设置了 ack=all,一定不会丢,要求是,你的 leader 接收到消息,所有的 follower 都同步到了消息之后,才认为本次写成功了。如果没满足这个条件,生产者会自动不断的重试,重试无限次。
九、Redis
1、数据类型
- String
常用命令: set,get,decr,incr,mget 等。
- Hash
常用命令: hget,hset,hgetall 等
- List
常用命令: lpush,rpush,lpop,rpop,lrange 等
可以通过 lrange 命令,就是从某个元素开始读取多少个元素,可以基于 list 实现分页查询。
- Set
常用命令: sadd,spop,smembers,sunion 等
- Sort Set
常用命令: zadd,zrange,zrem,zcard 等
2、Redis 如何实现 key 的过期删除?
定期删除和惰性删除的形式。
- 定期删除 Redis 每隔一段时间从设置过期时间的 key 集合中,随机抽取一些 key ,检查是否过期,如果已经过期做删除处理。
- 惰性删除 Redis 在 key 被访问的时候检查 key 是否过期,如果过期则删除。
3、Redis 的持久化机制
数据快照(RDB)+ 修改数据语句文件(AOF)
4、如何解决 Redis 缓存雪崩和缓存穿透?
-
缓存雪崩 缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
- 解决方式
- 事前:保证 Redis 集群的稳定性,发现机器宕机尽快补上,设置合适的内存淘汰策略。
- 事中:本地缓存 + 限流降级,避免大量请求落在数据库上。
- 事后:利用 Redis 持久化机制尽快恢复缓存。
- 解决方式
-
缓存穿透 一般是黑客故意去请求缓存中不存在的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。
- 解决方式 将不存在的数据列举到一个足够大的 map 上,这样遭到攻击时,直接拦截 map 中的请求,请求到数据库上面。或是把不存在的也做缓存,值为 null ,设置过期时间。
5、如何使用 Redis 实现消息队列?
Redis 实现消息队列依赖于 Redis 集群的稳定性,通常不建议使用。
- Redis 自带发布订阅功能,基于 publish 和 subscribe 命令。
- 使用 List 存储消息,lpush,rpop 分别发送接收消息。
十、Nginx
Nginx 是一款轻量级的 Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。 Nginx 主要提供反向代 理、负载均衡、动静分离(静态资源服务)等服务。
1、正向代理和反向代理
- 正向代理 代理客户端访问服务器。典型:VPN
- 反向代理 代替服务器接收客户端请求,然后转发给服务器,服务器接收请求并将处理的结果通过代理服务器转发给客户端。
2、负载均衡
将请求分摊到多台机器上去,高并发,增加吞吐量。
- 负载均衡算法
- 权重轮询
- fair
- ip_hash
- url_hash
3、动静分离
动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好了拆分以后,我们就可以根据静态资源的特点将其做缓存操作,这就是网站静态化处理的核心思路。
4、Nginx 四个组成部分
- Nginx 二进制可执行文件:由各模块源码编译出一个文件
- Nginx.conf 配置文件:控制 Nginx 行为
- acess.log 访问日志: 记录每一条 HTTP 请求信息
- error.log 错误日志:定位问题