面向对象
- 面向过程
注重事件的每一个步骤与顺序
特点:直接,高效
- 面向对象
注重事件的参与者
特点:更易于拓展,维护
面向对象三大特性
- 封装
明确标识允许被外部使用的所有成员函数和数据项
- 继承
继承基类,做出自己的改变或者扩展
- 多态
基于对象所属类的不同,外部对同一个方法进行调用,实际执行的逻辑不同
条件:继承,方法重写,父类引用指向子类对象
JDK JRE JVM
- JDK
开发工具
- JRE
Java运行环境
- JVM
虚拟机
== 和 equals
- ==
基本数据类型比较栈中的值,引用类型比较的是堆中内存对象的地址
- equals
默认也是使用 == 比较,不过通常会被重写
final
- 修饰类为最终类,不可被继承
String StringBuffer StringBuilder
- String
final 修饰,不可变,每次操作都会产生新的对象
- StringBuffer
线程安全,对象改变时,在原对象上进行操作
性能: StringBuilder > StringBuffer > String
重载和重写
- 重载
发生在同一个类中,方法参数名必须相同
- 重写
发生在父子类中,方法名和参数类必须相同
接口和抽象类的区别
- 抽象类可以存在普通的成员函数,而接口中只能存在public abstract 方法
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的
- 抽象类只能单继承,而接口可以多实现
接口设计目的 like a
接口设计的目的,是对行为进行抽象,可以强制不同的类有相同的行为,它只约束了行为的有无,但不对如何实现进行行为限制
抽象类设计目的 is a
先有子类,后有抽象类,对子类相同的行为抽象为一个派生类
List Set 区别
hashCode 与 equals
- hashCode
散列码,返回int整数,哈希码的作用确定该对象在哈希表中的索引位置,散列表存在的是键值对
ArrayList 和 LinkedList 区别
- ArrayList
基于动态数组,连续内存存储,支持下标访问,使用尾插法并且指定初始容量可以极大提升性能
- LinkedList
基于链表,可以存储在分散的内存中,适合数据插入以及删除操作,不适合查询
HashMap HashTale
- HashMap
线程不安全,允许键值为null
jdk8以后,当链表高度到8,并且数组长度到64则转变为红黑树,长度低于6,由红黑树退化为链表
- HashTable
线程安全,性能较低,不允许键值为null
ConcurrentHashMap原理
jdk7:
数据结构:ReentrantLock + segment + HashEntry,一个segment包含一个HashEntry数组,每个HashEntry又是一个链表结构
元素查询: 需要进行两次Hash,第一次hash 获取对应的segment,第二次获取HashEntry的下标
锁:segment分段锁, segment继承了ReentrantLock, 并发度为 segment 个数,锁定操作的segment,其他的segment不受影响
jdk8:
数据结构:
锁:
如何实现IOC
1:配置文件+包扫描路径
2:递归包扫描获取.class对象
3:反射,确定需要交给Spring管理的类
4:对需要注入的类进行依赖注入
字节码以及使用字节码的好处
Java类加载器
- boosstarp Classloader
- ExtClassloader
- AppClassLoader
双亲委托模型
Java中的异常体系
顶级父类:throwable
throwable包含两个子类 Exception Error
error:程序无法处理,会被迫停止运行
CheckedException:检查时异常
RuntimeException:运行时异常,只会导致当前此次调用失败
GC如何判断对象可以被回收
- 引用计数法
每一个对象有一个引用计数器,新增一个引用时计数器加1,引用释放时计算机减1,计数为0时可以被回收
- 可达性分析
从 GCRoots开始向下搜索,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,那么虚拟机就判断是可回收对象
GC Roots的对象有:
虚拟机栈(栈桢中的本地变量表)中引用的对象
方法区中的静态属性引用的对象
方法区中常量引用的对象
本地方法栈中引用的对象
Java 线程生命周期
- 锁池
- 等待池
ThreadLocal
使用场景
- 在对象进行跨层传输时,使用ThreadLocal可以避免多次传递,打破层次间的约束
- 线程间数据隔离
- 数据库连接,Session会话管理
内存泄漏原因,如何避免
并发的三大特性
- 原子性
关键字: synchronized
- 可见性
关键字: synchronized,volatile,final
- 有序性
关键字: synchronized,volatile
线程池中阻塞队列的作用
spring
容器框架,容纳JavaBean对象
AOP
IOC
- 容器对象
- 控制反转
- 依赖注入
BeanFactory 和 ApplicationContext
BeanFactory采用延时注入,只有在使用的时候,才会通过getBean()示例化
ApplicationContext 在容器启动的时候,一次性创建所有的Bean对象
Spring Bean 生命周期
- 解析类扫描包,获取BeanDefinition
- 如果有多个构造器,要推断构造方法
- 确定好构造方法后,实例化一个对象
- 对对象中@Autowired注解的属性进行属性填充
- 调用aware方法,比如BeanNameAware, BeanFactoryAware
- 调用BeanPostprocessor的初始化前的方法
- 调用初始化方法
- 调用BeanPostprocessor的初始化后的方法,这里会进行AOP
- 如果Bean对象是单例的,则放入单例池
- Bean对象的使用
- Bean对象的销毁
Spring Bean 作用域
- singleton: 默认每个容器中只有一个Bean的实例
- prototype: 每一个Bean 请求一个实例
- request: 每个Http请求中创建一个单例对象
- session: 每个Session中有一个Bean的实例
Bean 是线程安全的吗
Spring 框架中使用了那些设计模式
- 简单工厂
BeanFactory 中 通过getBean() 获取对象
- 工厂方法
在这里插入代码片
- 单例模式
- 适配器
- 装饰器模式
在这里插入代码片
- 动态代理
- 观察者模式
- 策略模式
spring 事务
- 编程式
- 申明式
事务的传播机制
- REQUIRED: 默认,如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务
- SUPPORTS: 如果当前存在事务,则加入这个事务,如果当前没有事务,则以非事务方式运行
- MANDATORY:如果当前存在事务,则加入这个事务,如果当前没有事务,则抛出异常
- REQUIRES_NEW: 创建一个新事务,如果当前存在事务,则进行挂起
- NOT_SUPPORTED: 以非事务方式运行,如果存在事务,则挂起当前事务
- NEVER: 不使用事务,如果当前存在事务,则抛出异常
Spring 事务失效
spring 事务的原理是AOP,所有AOP失效会导致事务失效
- 发生自调用时,类里边使用本类的方法
- 方法不是public的
- 数据库不支持事务(spring 事务依赖于数据库的事务)
- 没有被Spring进行管理
- 异常被吃掉,事务无法进行回滚
Bean 的装配方式
autowried属性有五种装配的方式
- no 缺省情况下,通过ref属性,手动进行装配
- byName 根据bean的属性名称进行装配
- byType 根据bean的属性类型进行装配
- constructor 类似byType,通过构造器的参数类型进行装配
- antodetect 如果有默认的构造器,则使用constructor ,否则使用byType
spring springmvc springboot
- spring
IOC容器,用来管理Bean对象,使用依赖注入实现控制反转,可以很好的整合各种框架,提供AOP机制
- springmvc
spring对web框架的一个解决方案,提供了一个控制器Servlet,用来接收请求,定义了一整套映射器,适配器,处理器,试图解析器
- springboot
spring 快速开发包,让编码更方便,简化配置,自定义start,开箱即用
springmvc 的工作流程
- 用户发送请求到DispatcherServlet
- DispatcherServlet 收到请求调用 HanderMapping 处理器映射器
- 通过url找到对应的处理器,生成处理器,以及处理器拦截器返回DispatcherServlet
- DispatcherServlet调用HanderAdapter 处理器适配器
- 适配器调用具体的处理器进行逻辑处理
- 处理得到ModelAndModel
SpringMvc 的九大组件
- HanderMapping
处理器映射器,<url,hander>映射关系,每一个url对应一个需要执行的处理器
- HanderAdapter
处理器适配器,handle真正执行处理逻辑
- viewResolver
视图解析器
Springboot 自动配置原理
springboot start
start就是定义一个starter的jar包,写一个@Configuration配置类,将Bean对象定义在配置类中,然后再starter包的META-INF/spring.factories中写入该配置文件,然后springboot会按照约定来加载这些配置类
嵌入式服务
mybatis优缺点
优点
- sql 写在xml里,统一管理,便于维护
- 与spring 集成很好
- 提供与java对象的映射关系
缺点
- 联表过多时,对sql功底有一定的要求
- sql 依赖于数据库,不可以随意迁移数据库
#{} 与${}
- #{} 是预编译处理,是占位符
- ${} 是字符串替换,是拼接符
- #{}经过变量替换后, #{}中的变量自动加上单引号
-
${}经过变量替换后,${}中的变量不会加上单引号
Mybatis插件
Mybatis 只针对parameterHander,ResultSetHandler,StatementHandler,Excutor 这四个接口的插件
插件编写:
1:实现Mybatis的Interceptor接口并复写intercept()方法
2:为插件编写注解,指定要拦截哪一个接口的方法
3:在配置文件中配置插件
索引
快速查找具有特定值的记录
原理:把无序的查询变成有序的查询
1:把创建了索引的列得内容进行排序
2:对排序结果生成倒排表
3:在倒排表上内容拼接数据地址链接
聚簇索引 和 非聚簇索引
- 聚簇索引
将数据存储与索引放在一起
优点:查询聚簇索引就可以直接查到数据
对于范围查询效率很高
- 非聚簇索引
叶子结点不存储数据
mysql 索引的数据结构
- B + 树索引
平衡的多叉树,一个父节点可以对应n个字节点
同层次的节点会有指针相互链接、
- 哈希索引
sql 慢查询解决
- 分析语句,是否加载了不需要的多余的数据列
- 分析语句的执行计划,获取使用索引的情况,之后修改语句或者添加索引,使语句尽可能的命中索引
- 查看表数据是否过大,如果是的话可以考虑分库分表
MVCC
接口的幂等性保证
- 唯一ID,数据库增加唯一约束
- 服务端提供发送token的接口
Spring cloud 和 Dubbo的区别
- 底层协议:springcloud基于Http协议,dubbo基于TCP协议,决定了dubbo的性能较好
- 注册中心:spring cloud 使用eureka ,dubbo 推荐使用zookeeper
eureka:AP 可用性
zookeeper:CP 一致性
- 模型定义:dubbo 将接口定义为服务,spring cloud 一个应用作为一个服务
dubbo:分布式
spring cloud:微服务
- 功能定位:spring cloud 是一个生态,而Dubbo只是关于服务调用的一种解决方案
Hystrix的实现机制
分布式容错框架
- 阻止故障的连锁反应,实现熔断
- 快速失败,实现服务降级
- 提供实时的监控和告警
资源隔离:线程隔离,信号量隔离
Spring cloud 核心组件以及作用
- Eureka:服务的注册与发现
- Ribbon:服务间发起请求的时候,做负载均衡
- Feign:基于Feign的动态代理机制,让调用远程和本地一样方便
- Hystrix:分布式容错
- Zuul:网管服务,也会成为Eureka下的应用,实现服务路由
Dubbo 架构设计及分层
角色
- 注册中心registry:服务的注册与发现
- 服务提供者provider:暴露服务
- 服务消费者consume:调用远程服务
- 监控中心:服务之间的调用次数,调用时间
- 容器container:服务容器
调用流程
- container容器负责启动,加载,运行provider
- provider向注册中心注册自己的服务
- consume向注册中心订阅自己的服务
- registry向consume提供服务提供者列表,如果provider有变更,则registry通过长连接将变更数据推送到consume
- consume调用provider,基于负载均衡进行调用
- consume调用provider的统计,基于短链接规定每分钟统计一次到monitor
分层
- 接口服务层(service):面向开发者,接口,实现等
- 配置层(config):对外配置接口,以serviceConfig和ReferenceConfig为中心
- 服务代理层(proxy):对于生产者和消费者,Dubbo会产生一个代理类封装调用细节
- 服务注册层(registry):封装服务地址的注册与发现,以服务URL为中心
- 路由层(cluster):封装多个提供者的路由和负载均衡
- 监控层(Monitor)
- 远程调用层(Protocal)
- 信息交换层(Exchange)
- 网络传输层(Transport)
- 数据序列化层
RabbitMq
- Broker:服务节点
- Queue:用来存储消息,多个消费者可以同时订阅同一个队列
- Exchange:生产者将消息发送到交换机,由交换机决定将此消息路由到一个或多个key中
- Binding:维护交换机和Queue的多对多关系
- RoutingKey:路由key,生产者发消息的时候,一般会指定一个RoutingKey,用来指定这个消息的流向
- 信道:复用TCP连接
如何保证消息的发送和接受
- 发送发确认:信道回调,信道设置为confirm模式,所有在信道上发布的消息都会分配一个唯一的ID
confirmCallback:信息到达Exchange成功则进行回调
ReturnCallback:消息失败时调用
服务熔断与服务降级
- 服务降级
服务降级是解决系统资源不足和海量业务请求之间的矛盾
- 服务熔断
熔断模式保护的事业务系统不被外部大流量或者下游系统异常而冲垮
系统限流
实现思路:拦截打到项目的前端请求
- 计算器法:单秒对请求进行计数,超过系统承受的最大域值,快速失败
- 滑动窗口计数法:将时间拆为更细的粒度
- 漏桶算法:固定的空桶 + 固定的处理线程(保护下游系统)
- 令牌桶算法:桶容量跟阈值相关,想完成请求,必须在桶里拿到令牌 (保护上游系统)
Redis 与 DB数据同步问题
- update DB -> update redis
可能出现redis缓存更新失败的情况
- deleted redis -> update DB
数据删除之后,如果数据改写的速度,低于第二次请求读取的速度,redis会再次加载未更新的就数据
- update DB -> deleted redis
DB 数据更新之后,再更新redis ,redis存储为变更后的新数据
- 访问串行化
1:先删除缓存,将更新数据库的操作放入有序队列中
2:从缓存查不到的查询操作,都进入有序队列
会面临的问题:
1:读请求积压,大量超时,导致数据库压力大
2:如何避免请求积压:设置多个有序队列,水平拆分,并行操作