Bootstrap

Java面试题复习

Java一轮复习

一、Java基础知识

基础知识

1、Java的特点

  • 对象、类库、平台、可靠、多线程

2、Java与c++的区别

  • 内存(访问(指针)、管理(GC))
  • 继承
  • 重载

3、数据类型

  • 8大基本数据类型
  • 与包装类的区别
  • 拆装箱(valueOf、intValue)
  • 缓存机制(装箱的时候)
    • byte、short、Integer、Long、Character

4、⭐String

  • String、StringBuffer、StringBuild的区别
    • 是否是线程安全的 synchronized
    • 是否是可变的
    • 性能的差异
  • 为什么string是不可变的 final
  • 字符串常量池
    • 作用、意义:避免重复创建浪费资源
    • intern方法
    • 常量折叠
    • 常见问题
      • new一个字符串创建了几个对象

5、常见知识

  • JDK、JRE、JVM
  • final(类、方法、基本数据类型、引用类型)
  • static 静态的、全局的,属于类
  • ==和equals
  • equals和hashcode

面向对象

1、特征:封装继承多态

2、面向过程和面向对象

  • 面向过程是把解决问题的过程写成函数去执行
  • 面向对象是先抽象成对象,再用对象的方法进行解决

3、接口和抽象类

  • 相同点
    • 都不能被实例化
    • 都包含抽象的方法
    • 都可以有默认的方法
  • 不同
    • 意义
      • 类之间的关系;行为的约束
    • 继承的方式
    • 成员变量

4、深拷贝和浅拷贝:是否被拷贝引用类型的成员变量

5、类之间的关系 (4):依赖、关联(组合、聚合)、继承、实现

6、泛型:java是伪泛型,用于类型检查,编译的时候会进行类型擦除

  • 指定了类型也可以放其他的类型,利用反射拿到add方法

7、比较器:comparable和comparator

  • comparable是内部比较,实现接口重写compareTo方法
  • comparator是外部比较器,compare是函数式接口(new TreeMap<>((Integer o1, Integer o2)-> o2 - o1 );)

异常(Throwable)

1、错误(编译器不会检查、程序无法处理):OOM

2、异常(程序可以通过catch捕获)

  • 受检查的异常 CheckedException:IO相关、classNotFound
  • 不受检查的异常(运行时异常) RuntimeException:空指针

反射

1、优缺点

  • 灵活
  • 安全问题、开销

2、原理:创建类时会创建Class的对象

3、方式

  • 对象:.getClass
  • 类:.class
  • 类路径:Class.forName(“类路径”)

注解(元数据)

1、本质是接口

2、编译期扫描,利用反射

IO和序列化

1、Unix的5中IO

  • 同步阻塞、同步非阻塞、IO多路复用、异步IO、信号驱动IO

2、java中的3中IO

  • BIO
  • ⭐NIO(New IO、Not Block IO):用一个线程监听,对应的事情在启用其他线程去做
    • Selector:
    • Channel
    • Buffer
  • AIO

3、IO分类

  • 流向:输入输出
  • 类型:
    • 字符:字符转字节很耗时间,并且不知道对应编码很容易乱码
    • 字节
  • 角色:节点流、处理流

4、IO对应设计模式

  • 适配器模式
    • InputStream想用Reader这种可以自由操作字符,需要适配器InputStreamReader转换
  • 装饰者模式
    • InputStream可以read一个字节,包装成Reader可以read一个字节,包装成BufferReader可以read一个字符串

5、序列化

  • 场景:网络传输、持久化 -> 将数据结构(list)或者对象转为二进制流
  • 序列化方式
    • java.io.Serializable
      • serialVersionUID用于版本号控制
    • 其他(例如grpc的protobuf等)
  • 阻止某个字段序列化
    • Transient:加在属性上
    • 静态变量不加也不会序列化

jdk1.8的新特性

1、Lambda表达式

  • @FunctionInterface可以使用lambda表达式代替
    • 4种函数式接口类型

2、流式计算:Stream

  • 存储交给容器和数据库,计算交给流
  • 类型:集合、数组、io、静态

3、时间类API

  • 新增java.time中LocalTime
    • 解决时区问题
    • 解决格式化问题
    • 日期和时间分离

4、Optional:减少空指针异常

二、容器

Collection

1、List

  • ArrayList
    • 实现:object数组
    • 线程不安全 -> CopyOnWriteArrayList
    • ⭐扩容
      • 初始是0,第一次到默认值10,每次变为1.5倍(每次扩一半)
      • Arrays.CopyOf 本质上是调用System.arraycopy方法
      • add前一次到位,ensureCapacity
  • Vector
    • 实现:object数组
    • 线程安全:synchronized
    • 与ArrayList的区别
      • 线程安全、扩容(vector每次扩一倍)
  • LinkedList
    • 实现:双向链表
    • 线程不安全 -> ConcurrentLinkedQueue
    • ⭐与ArrayList的区别
      • 数据结构不同
      • 存储不同(前后指针、扩容的部分)
      • 访问不同(随机访问)
      • 新增和删除不同(数组和链表的不同)

2、Set

  • HashSet
    • 实现:HashMap
    • 线程不安全
  • TreeSet
    • 实现:红黑树
    • 线程不安全

3、Queue

  • PrioriQueue
    • 实现:Object数组实现的小顶堆
    • 线程不安全
  • Duque(接口)
    • 实现:ArrayDuque:Object数组 + 双指针

4、Collections工具类

  • 查找:BinarySearch
  • 排序:sort
  • 加锁:synchronizedList

Map

1、⭐HashMap

  • 实现:拉链法(数组+链表)
  • 线程不安全 -> ConcurrentHashMap
  • ⭐扩容
    • 默认为16,当指定大小时扩到原来的2的幂次倍(方便散列)
      • hash % length == hash & (length - 1),前提是length是2的幂次方
      • 扩容会rehash
    • 当链表长度大于8时,先检查数组长度是否大于64,没有就先扩容,再将链表转为红黑树
  • ⭐put和get原理
    • put,先封装成node,再用hashcode进行散列
    • get,利用hashcode找到节点
  • ⭐3大参数
    • capacity,当前数组长度
    • loadFactory,加载因子
    • threshold,阈值,超过这个要扩容,等于上面俩的乘积

2、HashTable

  • 实现:数组+链表
  • 线程安全:线程安全,用synchronized锁整张表
  • 扩容:默认值为11,扩容为2n+1
  • ⭐与HashMap的区别
    • 数据结构(链表大于8不会变红黑树)
    • 线程安全/效率
    • 存储(能不能存null)
    • 扩容
  • ⭐与concurrentHashMap比较
    • synchronized锁整张表
    • CAS+自旋拿头节点,synchronized锁头节点

3、TreeMap

  • 实现:红黑树

4、为什么要用容器

  • 存储数据结构和数据类型的多样性

三、JVM

内存模型

1、进程

    • 存储对象实例和数组
    • 分类:新生代、老生代
  • 方法区
    • 存储class文件获取的相关信息,1.8后叫元空间
    • 结构
      • 类元信息:类的字段、方法、版本
      • 运行时常量池:字面量、符号引用
      • 字符串常量池(1.8后移动到堆中)
      • 静态变量(1.8后移动到堆中)
      • JIT即时编译缓存

2、线程

  • 程序计数器
    • 读取指令,记录代码执行的位置
    • 代码的执行和上下文的切换
  • VM栈
    • 方法的调用(压栈)
    • 栈帧
      • 局部变量表:局部变量,对象的引用
      • 操作数栈:临时变量和中间结果
      • 动态链接
      • 方法返回地址
  • 本地方法栈
    • 同vm栈,调用的是本地库中的方法

3、本地内存(堆外内存)

  • 元空间(方法区)
  • 直接内存:NIO作为缓冲区

垃圾回收机制(GC)

1、垃圾回收算法

  • 分类

    • 标记-清除:碎片
    • 标记-复制
    • 标记-整理
  • 标记算法

    • 三色标记

      • 基本算法
        • 白色:1、使用可达性算法分析,初始都为白色;2、尚未被垃圾回收器访问;3、垃圾回收器标记后还未白色为不可达
        • 灰色:对象被垃圾回收器访问过,但对象上至少还有一个引用没扫描
        • 黑色:访问过且所以引用都被访问过(不会指向白色对象)
      • 过程
        1. 初始时,全部对象都是白色的
        2. GC Roots直接引用的对象变成灰色
        3. 从灰色集合中获取元素:
          • 将本对象直接引用的对象标记为灰色
          • 将本对象标记为黑色
        4. 重复步骤3,直到灰色的对象集合变为空
        5. 结束后,仍然被标记为白色的对象就是不可达对象,视为垃圾对象
      • 缺陷:针对并发标记
        • 多标
          • 并发执行的时候程序将一个已标记的对象的引用断开(浮动垃圾)
        • 漏标
          • 并发标记访问该对象将其置为黑色后程序又添加了引用,该对象没有被访问到
    • 读写屏障

      Object E = D.next;
      D.next = null;    
      B.next = E;     
      

      img

      • 读屏障:第一步,当读取引用对象的时候,一律记录下来
      • 写屏障:第二、三步,当黑色指向白色的引用被建立时,在属性赋值的前后加入一些处理,类似于AOP
    • 增量更新和原始快照:主要与写屏障结合

      • 原始快照(Snapshot At The Beginning,SATB)
        • 当灰色对象指向白色对象的引用被断开时,就将这条引用关系记录下来。当扫描结束后,再以这些灰色对象为根,重新扫描一次。
      • 增量更新
        • 当黑色指向白色的引用被建立时,就将这个新的引用关系记录下来,等扫描结束后,再以这些记录中的黑色对象为根,重新扫描一次。相当于黑色对象一旦建立了指向白色对象的引用,就会变为灰色对象。
  • ⭐分代收集

    • 部分收集
      • Minor GC
        • 主要算法:标记-复制:新生代,因为大量的对象死亡,存活少
        • 出现原因:新生代空间不足
        • 过程:
          • 先进行空间分配担保,如果老生代没有足够空间,就Major GC有时也叫整堆收集
          • 将Eden和Survivor0中存活的对象移动到Survivor1中,然后清空这两个区域,交换1和0的位置
          • 每次Minor GC存活对象年龄+1,年龄为15时移到老生代
      • Major GC
        • 主要算法:标记-清除、标记-整理,大量对象存活,没有额外空间进行复制
        • 有时Major GC也指整堆收集
      • 混合GC
    • 整堆收集
      • 收集java堆和方法区
      • 原因:
        • 老生代空间不足
        • 方法区空间不足
        • System.gc
        • 分配担保不足

2、垃圾收集器

  • Serial收集器

    • 新生代收集器
    • GC算法:新生代标记复制,老生代标记整理
    • 特点:单线程
  • ParNew收集器

    • 新生代
    • Serial+多线程
  • Parallel Scavenge

    • 新生代收集器
    • GC算法:新生代标记复制,老生代标记整理
    • 特点:关注吞吐量(cpu利用率)
    • JDK1.8 默认使用的是 Parallel Scavenge + Parallel Old
  • Serial Old

  • Parallel Old

  • ⭐CMS(并发标记清除)

    • GC算法:标记清除
    • 标记方法:写屏障 + 增量更新
    • 特点:关注停止时间(用户体验)
    • 过程
      • 初始标记:记录与root直接相连对象,STW: Stop-The-World
      • 并发标记:重新寻找存活对象
      • 重新标记:记录上一阶段中落下的存活对象,STW: Stop-The-World
      • 并发清除:标记清除
    • 优缺点
      • 并发收集,停顿时间,用户体验
      • cpu资源敏感,无法清除浮动垃圾(并发标记中产生的)
  • ⭐G1收集器

    • 算法:局部标记复制,整体是标记整理

    • 标记方法:写屏障+SATB

    • 特点:关注吞吐量

      • 分代收集

        • minor gc(stw)
        1. 初始标记
        2. rset
        3. 复制
        • mix gc
        1. 初始标记(stw)
        2. 并发标记
        3. 最终标记(stw)
        4. 清除(stw)
      • 并行与并发

      • 可预测停止时间

      • 空间整合

    • 缺点

      • 大内存,适合服务器

3、回收

  • 类的回收
    • 所有实例被回收
    • 加载器被回收
    • 没有被引用
  • 对象的回收
    • 可达性分析
    • 引用计数法
  • 常量的回收
    • 没有string对象引用

类的生命周期(5)

1、类的加载:磁盘加载到内存

  • 类的加载器
    • BootstrapClassLoader:顶层,java自带的类
    • ExtendClassLoader:java拓展类
    • AppClassLoader:自己和第三方的类
  • 类的加载方式
    • 双亲委派机制
      • 先交给父类加载器去加载
      • 好处:避免类重复,避免核心api被篡改
  • 类的加载过程
    • 获取类的二进制流
    • 将二进制转为方法区数据结构存储
    • 在堆中创建Class对象

2、类的连接:读取类

  • 验证:格式是否合规
  • 准备:静态变量分配内存并付初始值
  • 解析:符号引用转成直接引用

3、类的初始化

  • 给静态变量赋值

4、类的使用

5、类的卸载

  • 没有实例
  • 没有加载器
  • 没有引用

对象

1、对象的生命周期(3)

(1)对象的创建

  • 加载类信息(方法区)
  • 在堆中分配空间
  • 初始化零值
  • 设置对象头
  • init方法

(2)对象的使用

(3)对象的死亡

  • 引用的分类
    • 强引用
    • 软引用
    • 弱引用
    • 虚引用
  • 对象是否需要GC的判断
    • 可达性分析
      • GC Root的对象(vm栈中的引用的对象、本地方法栈的引用的对象、方法区类的静态属性引用的对象)
      • 对象回收:不会直接回收,会判断第二次
    • 引用计数法

2、对象的内存布局

  • 对象头
    • mark words
      • 锁信息
      • hashcode
      • 分代年龄
    • class point
    • 数组长度
  • 实例数据
  • 对齐填充:8个字节的整数倍

3、对象的访问

  • 句柄:局部变量表的reference 指向堆中的一个表,表里分别指向对象和类
  • 指针:局部变量表的reference 中存储的直接就是对象的地址,由对象指向类

jvm调优

1、目的:减少gc频率

2、堆的调优

  • 大小:
    • 最小-Xms:2G
    • 最大-Xmx:2G
  • 新生代
    • -Xmn:2G
    • -XX:NewSize=2G,-XX:MaxNewSize:2G
    • -XX:SurvivorRatio=8(Eden:Survivor = 8:2)
  • 老生代
    • -XX:NewRatio=2(新生代:老年代 = 1:2)
  • 永久代
    • -XX:MetaspaceSize

2、cms参数

3、g1参数

4、jvm优化

  • cpu满排查
    • jps
    • top -Hp pid
    • jstack pid 打印线程
  • 内存满排查
    • jps
    • jinfo pid 查看虚拟机情况
    • jstat gc pid 查看gc情况
    • jmap -heap pid堆信息
    • jmap -histo:live pid
    • jmap -F -dump:format=b,file = ./jmap.phrof pid

四、并发编程

线程

1、线程与进程

  • 进程是程序的执行的基本单位,线程是最小单位
  • 一个进程包含多个线程,线程共享进程中的资源
  • 线程也有私有的结构

2、线程与协程

  • 轻量级线程,用户态线程

3、多线程

  • 为什么要多线程
    • 多核优势
    • 发展趋势
  • 引发的问题
    • 内存泄漏 ThreadLocal
    • 死锁
      • 请求与保持
      • 循环等待
      • 不剥夺
      • 互斥
    • 线程不安全

4、线程的生命周期

  • 创建
    • 继承Thread
    • Runnerable
    • Callable 有返回值
    • 线程池
  • 等待
  • 等待超时
  • 运行/就绪
  • 阻塞
  • 死亡

5、内存结构

  • 程序计数器
  • vm栈
  • 本地方法栈

6、ThreadLocal

  • 场景:每个线程有单独的实例
  • 实现:将自己作为键保存在thread中的threadlocalmap中
  • 缺点
    • 内存泄漏
      • map的key(ThreadLocal)为弱引用,因为gc时需要回收threadlocal
      • value是强引用,一旦key被回收,value就不可见了,导致内存泄漏,所以要及时remove

锁机制

1、宏观分类

  • 乐观锁
    • 定义:每次在操作数据的时候都没人改
    • 代表:CAS,对比交换
      • ABA问题 :一开始为A,被改成B,又改回来A -> 版本号机制
  • 悲观锁
    • 定义:每次在操作数据的时候都有人改
    • 代表:
      • ⭐Synchronized锁
        • 用法
          • 方法:ACC_SYNCHRONIZED
          • 同步代码块:monitorenter monitorexit
        • 锁升级
          • 无锁 01:CAS
          • 偏向锁 01:很少的线程进行操作,记录线程的id,下次来直接拿锁不用验证
          • 轻量级锁 00:双向绑定(LockRecord、markword)
          • 重量级锁 10:Markword指向ObjectMonitor
      • ⭐Lock
        • ReentrantLock(与Syn的区别)
          • 基于Api(类),基于JVM(关键字)
          • 等待可中断
          • 选择性通知(condition)
          • 获得锁的状态
          • 需要手动释放
          • 实现了公平锁
        • 实现:AQS
          • 抽象的队列同步器
          • 通过应该双向队列维护等待进程
          • CountDownLatch 、Semaphore、CycleBarry

2、其他分类

  • 可重入锁
    • 一旦线程得到锁,就可以再次获得锁,避免死锁,但要释放多次
  • 公平锁/非公平锁
    • 公平锁,线程要拿锁需要在等待队列中排队,一定时间后超时
    • 非公平锁,线程先尝试获得锁,不行再排队
  • 共享锁和独占锁
    • 独占锁:互斥
    • 共享锁:读锁

3、锁的优化

  • 锁升级
  • 锁粗化
    • 检测到一串操作对同一把锁进行操作,就把锁的范围扩大
  • 锁消除
    • 堆上的某个数据不会逃逸出去被其他线程利用,认为不需要锁,就消除

volatile关键字

1、JMM

  • 线程使用变量时,先拷到本地,用完再刷回去
  • ⭐并发的特性
    • 原子性
    • 有序性
    • 可见性

2、⭐volatile

  • 特性:保证有序性(禁止指令重排)、保证可见性;修饰变量/属性
  • 缺点:不保证原子性

并发组件

1、原子类

  • 保证原子性
  • 原理:CAS+自旋
  • 代表
    • 基本类型:AtomInteger(Increment)
    • 数组:AtomIntegerArray

2、⭐线程池

  • 为什么用线程池
    • 减低资源消耗
    • 提高响应速度
    • 方便管理
  • 3大方法(Executors):队列长度最大为Integer.MAXVALUE导致OOM
    • 单个newSingleThreadExecutor()
    • 固定newFixThreadExecutor()
    • 可伸缩newCacheThreadExecutor()
  • 7大参数:ThreadPoolExecutor
    • 核心线程数:最少工作的线程
    • 最大线程数:当队列满了最多工作的线程
    • 工作队列:当达到核心线程数后将任务加入队列,阻塞队列
    • 等待时间:任务在线程池中等待时间
    • 时间单位:TimeUtil
    • 线程池创建方式:默认
    • 拒绝策略
      • AbortPolicy 直接抛异常
      • CallerRunsPolicy 让提交的那个线程干
      • DiscardPolicy 直接丢弃
      • DiscardOldestPolicy 把第一个等待的丢了执行这个

并发容器

  • ConcurrentHashMap
  • CopyOnWriteArrayList
  • ConcurrentLinkedQueue
  • BlockQueue(用的ReentrantLock,队列满了就会阻塞)

限流算法

1、定义

  • 限流是指在系统面临高并发、大流量请求的情况下,限制新的流量对系统的访问,从而保证系统服务的安全性
  • 在计算机网络中,限流就是控制网络接口发送或接收请求的速率,它可防止DoS攻击和限制Web爬虫

2、⭐限流算法

  • 计数器法
    • 定义:最简单的限流算法就是计数限流了,例如系统能1分钟同时处理100个请求,保存一个计数器,处理了一个请求,计数器加一,一个请求处理完毕之后计数器减一
    • 场景:指定线程池大小,指定数据库连接池大小,nginx连接数
    • 具体方法(原子类、countDownLatch)
      • 在一开始的时候,设置一个计数器counter,每当一个请求过来的时候,counter就加1,如果counter的值大于100 并且该请求与第一个请求的间隔时间还在1分钟之内,那么说明请求数过多,拒绝访问
      • 如果该请求与第一个请求的间隔时间大于1分钟,且counter的值还在限流范围内,那么就重置counter
    • 缺点:临界值问题
      • 在0:59时,瞬间发送了100个请求,并且1:00有瞬间发送了100个请求
    • 解决:滑动时间窗口
      • 将一个时间单位划分的更细,每个小窗口设置一个计数器
      • 问题:可以解决临界值问题,但依然无法解决短时间的突发流量(10ms内来了1wQPS)
  • 漏桶算法
    • 定义:漏桶算法限流的基本原理为:水(对应请求)从进水口进入到漏桶里,漏桶以一定的速度出水(请求放行),当水流入速度过大,桶内的总水量大于桶容量会直接溢出
      • 进水口(对应客户端请求)以任意速率流入进水漏桶(流入速率随机)
      • 漏桶的容量是固定的,出水(放行)速率也是固定的(流出速率固定)
      • 漏桶的容量是不变的,如果处理速率太慢,桶内水量就会超出了桶的容量,则后面流入的水就会溢出,表示请求拒绝
    • 场景
      • 削峰:有大量流量进入时,会发生溢出,从而限流保护服务可用
      • 缓冲:不至于直接请求到服务器,缓冲压力
    • 实现:阻塞队列BlockQueue
    • 缺点:应对突发流量时,无法灵活应对(突然从100QPS(每秒查询率)变到1wQPS)(太平滑了也不好)
  • 令牌桶算法
    • 定义:
      • 所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;
      • 根据限流大小,设置按照一定的速率往桶里添加令牌;
      • 桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;
      • 请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除;
      • 令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保证足够的限流;
    • 好处:可以自定义速率,灵活的应对突发情况
  • 分布式限流
    • GateWay限流
    • Nginx限流:漏桶
    • Redis+Lua脚本限流

五、Spring框架

Spring基础

1、定义:轻量级Java开发框架

2、⭐特点

  • IoC控制反转
    • 将对象的创建和管理交给Spring框架来做
  • AOP面向切面编程
    • 将与业务代码无关但被业务代码共同调用的部分封装起来,降低耦合
    • 分类
      • Spring AOP
        • 实现方式:动态代理
          • JDK 动态代理:基于接口的
          • Cglib动态代理:基于类/继承的
      • AspectJ AOP
        • 与SpringAOP的区别
          • 增强时机不同,spring是运行时,aspectJ是编译时
          • AspectJ性能更好

3、Spring的模块

  • Data模块:jdbc、orm
  • Web模块
  • AOP
  • Aspects
  • Spring Core:Bean、提供IOC
  • Test

4、⭐SpringBean

  • 定义:SpringBean就是被Spring管理的对象
  • 注解
    • @Component
    • @Service
    • @Repository
    • @Controller
    • @Configuration + @Bean:作用于方法上返回bean
  • 注入
    • @Autowired:byType
    • @Resource:byName
    • @Inject
  • 作用域
    • Singleton:全局唯一的实例
    • prototype:原型,每次请求都会创建新的
    • request:每次http请求创建,仅在这个请求内有效
    • session:会话中有效
    • global-session
  • ⭐Bean的生命周期(7)
    • 解析
      • 通过xml/注解/配置类进行找到需要装配的bean,并将其封装为beanDefinition
        • Class中的描述信息太少,String用BeanDefinition来描述一个bean对象,包括class信息、自动绑定模式(byname、bytype)
    • 注册
      • 调用BeanDefinitionRegistry的registry方法进行注册,将bean按照<名字,BeanDefinition>的形式保存在BeanDeifintionMap中
    • 获取
      • 调用AbstractBeanFactory的doGetBean方法获取bean对象
        • 检查三级缓存中有没有这个对象
        • 尝试从父容器中获取对象
    • 实例化(创建):一般说实例化是从这里开始,上面说的是加载过程
      • 判断bean的作用域、类是否已经加载
      • 执行前置的beanpostprocessor函数
      • bean的实例化并放入三级缓存中
      • 执行后置函数,postprocessorafterInstantiation
    • 依赖注入/属性填充
      • 给属性赋值
      • ⭐循环依赖问题
        • 三级缓存
          • SingletonObject
          • EarlySingletonObject
          • SingletonFactory
        • 过程:当A实例化后就放入第三级缓存中,当检查到有依赖B时先查看缓存中是否有对象,有的话就继续进行(如果在3级缓存中就把他放入2级缓存),没有就先执行依赖对象B的实例化过程
        • 为什么要3级缓存?
          • 原因:当需要产生代理对象的时候,B从三级缓存中拿出A,然后会将A的代理对象A’放入第二级缓存
            • 如果去掉第三级,A在实例化的时候就得放入代理对象
            • 如果去掉第二级,同样循环依赖A的C对象也会产生一个A的代理对象A’',导致依赖的不是同一个对象
    • 初始化
      • 是否实现了Aware接口
      • 前置函数
      • 执行init方法
        • 是否实现了initializationBean接口
        • 是否有initMethod方法
      • 后置函数:AOP,生成代理对象
    • 销毁
      • DisposalBean的destroy方法
      • 是否有自定义的destroy方法

5、BeanFactory和ApplicationContext(待进一步了解)

  • 相同点:都是spring的IoC容器
  • 不同点
    • 功能不同:A是B的接口的子类
    • 加载Bean的方式不同:懒加载和一次性加载
    • 创建方式不同:编程、配置
    • 注册方式不同:手动、自动

6、事务(声明式事务:@Transaction)

  • 作用范围
    • 方法
    • 类:所有方法
    • 接口:不推荐
  • 参数
    • 传播级别:A调用了B,B回滚,A回滚吗
      • 默认是会
      • 也可以设置不回滚
    • 隔离级别
      • default(按数据库的来)
    • ……

7、设计模式

  • 单例:bean
  • 工厂:bean的创建
  • 代理:aop

8、MyBits

  • 半ORM映射工具(Object Relational Mapping)
  • 二级缓存
  • 主键生成策略
    • 自增
    • uuid
    • redis生成
    • 雪花

SpringMVC

1、是Spring中一个重要模块(Web),思想是将业务、数据和视图分离

2、常用注解

  • @PathVariable:路径传值
  • @RequestParam:接收传参
  • @RequestBody:json解析成对象

SpringBoot

1、目的:简化Spring的配置和开发流程

  • 创建独立的spring应用程序
  • 嵌入式的tomcat
  • 简化maven配置
  • 自动配置spring

2、⭐SpringBoot的自动装配原理:@SpringBootApplication

  • @SpringBootApplication注解可以分解为3个注解
    • @ComponentScan,扫描路径下的所有bean并加载
    • @SpringBootConfiguration实际上也是@Configure配置类
    • @EnableAutoConfiguraion注解中@import了一个@AutoConfigurationImportSelector类,会调用SelectImports方法从Meta-INF下的spring-factories中加载配置类到IoC容器中,然后再加载他们import的类完成自动装配

SpringCloud

1、微服务

  • 微服务是分布式架构的一种,将单体架构中高度耦合的代码拆解成多个项目,每个项目独立开发和部署完成一部分业务称为一个微服务。多个微服务组成微服务集群。

  • spring cloud是微服务系统架构的一站式解决方案

2、spring cloud的优缺点

  • 优点
    • (低耦合)代码耦合低,模块开发独立
    • (低成本)减轻了单个模块的开发成本
    • (低配置)配置简单,只需要加注释
    • (跨平台)支持不同语言不同平台
    • (不同库)不同模块可以使用不同的数据库
  • 缺点
    • 微服务多,治理成本高
    • 分布式开发成本高(考虑容错等)

3、主要组成部分(Spring Cloud Netflix)

  • API网关
    • 根据请求不同定位到不同的微服务,屏蔽真正的地址
    • 组件:Zuul、Nacos(对比)、Nginx、Gateway
  • 负载均衡
    • 将网络流量分到多个服务器上,提高整体的效率
    • 组件:Feign、Ribbon
  • 注册发现
    • 服务将自己的模块信息注册到公共组件让调用者可以找到
    • 组件:
      • 集中式:Nginx
        • CP:一致性、分区容错性
        • 选举master会导致不可用
      • 进程式:Eureka
        • AP:可用性、分区容错性
          • 节点间是平等的
          • 查到的消息
          • 自我保护机制(一段时间(90s)没响应进入,等待恢复退出)
  • 通信方式
    • SpringCloud用的是Http(Restful),也可以用RPC的方式
  • 容错机制
    • 服务的调用过程可能会出问题
    • 断路器
      • 监听故障,发送一个预期的备用响应,避免长时间等待或者抛出异常引起雪崩
      • 状态:开、半开、关闭
    • 概念
      • 扇出:服务A调用B,B调用C,调用链
      • 雪崩:某个服务错误导致等待占用更多的资源最终导致系统崩溃
        • 服务降级:关闭一些服务
        • 服务熔断:多次调用失败就直接熔断,返回预设响应
        • 服务隔离:不同http请求用不同的线程池
    • 组件:Hystrix
  • 配置中心
    • 统一配置
    • 组件:Spring cloud Config
  • 消息总线
    • 配合config实现配置的动态刷新
    • 组件:spring cloud Bus —— 消息中间件实现(RabbitMQ、Kafka)
  • 消息驱动
    • 屏蔽消息中间件的差异
    • 组件:springcloud stream
  • 链路追踪
    • 请求链路
    • 组件:spring cloud sleuth

3、spring cloud与dubbo的区别

  • 定位不同:SpringCloud定位为微服务架构下的一站式解决方案;Dubbo 关注点主要在于服务的调用和治理
  • 生态环境不同:SpringCloud依托于Spring平台,具备更加完善的生态体系;而Dubbo一开始只是做RPC远程调用,生态相对匮乏,现在逐渐丰富起来
  • 调用方式:SpringCloud是采用Http协议做远程调用,接口一般是Rest风格,比较灵活;Dubbo使用RPC进行调用。
  • 组件差异比较多,例如SpringCloud注册中心一般用Eureka,而Dubbo用的是Zookeeper

4、补充:RPC框架

  • rpc与http
    • rpc是一种设计,http是一种协议
    • rpc一般有传输协议和序列化协议
;