spring
1.spring有哪些部分组成
Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);
Spring Core:核心类库,所有功能都依赖于该类库,提供IOC和DI服务;
Spring AOP:AOP服务;
Spring Web:提供了基本的面向Web的综合特性,提供对常见框架如Struts2的支持,Spring能够管理这些框架,将Spring的资源注入给框架,也能在这些框架的前后插入拦截器;
Spring MVC:提供面向Web应用的Model-View-Controller,即MVC实现。
Spring DAO:对JDBC的抽象封装,简化了数据访问异常的处理,并能统一管理JDBC事务;
Spring ORM:对现有的ORM框架的支持;
2.spring的启动流程
加载配置文件:Spring框架首先会读取并加载应用程序的配置文件。配置文件可以是XML文件(如applicationContext.xml)或者注解类(如@Configuration)。
创建Spring容器:Spring会根据配置文件中定义的Bean定义,创建一个容器(Application Context)。容器是Spring框架的核心,负责管理和组织各个Bean。
实例化Bean:容器根据配置文件中的Bean定义,在需要时实例化相应的Bean对象。实例化过程可以通过构造函数、工厂方法或者依赖注入来完成。
注入依赖:容器会自动为实例化的Bean对象注入其依赖的其他Bean对象。
执行自定义初始化方法:如果Bean类实现了InitializingBean接口或者在配置文件中指定了初始化方法,容器会在完成依赖注入后调用Bean的初始化方法。
Bean后置处理:容器会对Bean进行一些额外的处理,例如应用BeanPostProcessor接口实现类中定义的逻辑。
Bean准备就绪:当所有的Bean都初始化完成并且准备就绪时,Spring容器准备好为应用程序提供服务了。
执行应用程序:根据应用程序的需要,可以调用合适的方法或者触发事件来执行相应的应用程序逻辑。
3.spring中bean的生命周期
实例化,赋值,初始化,销毁
4.spring的bean默认单例的,怎么将其变为多例
将singleton属性设置为prototype
5.bean的注入方式
setter,构造器,注解
6.bean的装配方式
no byname(@resource) bytype(@autowrite) 构造函数 自动
7.spring的事务机制
编程式事务(TransactionTemplate)
声明式事务(@Transaction(异常类型),方法不是public时会失效)
8.spring的事务隔离级别
ISOLATION_DEFAULT:默认的隔离级别,同数据库
ISOLATION_READ_UNCOMMITTED:未提交读,允许事务在执行过程中,读取其他事务未提交的数据。(会出现幻读、脏读、不可重复读)
ISOLATION_READ_COMMITTED:提交读,允许事务在执行过程中,读取其他事务已经提交的数据。(会造成幻读、不可重复读)
ISOLATION_REPEATABLE_READ:可重复读,在同一个事务内,任意时刻的查询结果都是一致的。会造成幻读)
ISOLATION_SERIALIZABLE:所有事务逐个依次执行。
脏读 :表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录 A,此时该事务还未提交,然后另一个事务尝试读取到了记录 A。
不可重复读 :是指在一个事务内,多次读同一数据,值发生修改。
幻读 :指同一个事务内多次查询返回的结果集不一样。比如同一个事务 A 第一次查询时候有 n 条记录,但是第二次同等条件下查询却有 n+1 条记录,这就好像产生了幻觉。
9.自定义注解的实现
使用@Target指定注解作用范围
使用@Retention指定注解的生命周期
springboot
1.springboot的启动流程
通过main方法 启动springboot,首先进入run方法
run方法新建SpringApplication对象,创建并启动计时监控类
初始化应用应用参数
根据运行监听器和参数准备spring环境
创建,准备,刷新应用上下文
停止计时监控器类
发布应用上下文 启动完成事件
最后返回应用上下文
2.springboot的静态首页可以放在那里
/resources/static目录下
也可以子自定义静态资源位置,在application.yml文件中配置static-locations指定目录
3.springboot静态资源的优先级
默认resource/static->public
也可以自定义指定spring.webservices.wsdl-locations=classpath:/staticNew
4.springboot热部署的方式
idea设置spring-boot-devtools
jrebel插件
springcloud
1.怎么实现服务的注册
在配置文件中配置服务名,注册的服务中心地址
启动类添加注解@EnableEurekaServer
2.怎么使用feigin
提供外部接口,添加注解@FeiginClient补充服务名称和映射地址
3.ribbon的使用
负载均衡:默认轮询,还提供随机,最优可用,响应速度
定义RestTemplate添加注解@Bean@LoadBalanced,通过restTemolate发起请求
4.zuul网关的作用
处理http请求,拦截,监控,身份验证
zuul仅支持同步,可用配套多个微服务框架
5.gateway的作用
处理http请求,拦截,监控,身份验证,对比zuul还能实现负载均衡
gateway支持异步,但指配套与springcloud,吞吐量比zuul高
Dubbo
1.dubbo和springCloud的区别
dubbo是基于rpc(基于底层tcp,不需要通过http包装,效率更高)协议的,不能跨平台,一般使用xml注释
cloud是基于http协议的,可以跨平台,一般使用注解
2.dubbo默认的通信框架
netty(默认):异步事件驱动框架,高并发,次延迟
mina:基于java nio的通信框架
3.dubbo的声明式缓存
分为类级别和方法级别的缓存,将cache设置为true,默认大小1000,超过会根据lur策略保留热门缓存
4.dubbo的容错策略
失败自动切换,失败立刻抛出异常,失败重发,失败忽略,并行调用,容错合并
5.dubbo的动态代理
一般使用jdk动态代理,是基于proxyFactory来实现
还有javassist动态代理
6.dubbo怎么设置版本号
xml:通过version设置
可以用来新旧版本的升级过渡
7.dubbo的负载均衡
通过loadBalance实现
有随机,轮询,权重,最短时间相应,最少链接,一致性哈希
Zookeeper
1.zookeeper的数据结构
zookeeper的数据结构称之为节点,最小节点是zndoe,是一种树桩结构
2.zookeeper的节点类型
持久性节点,临时性节点,顺序性持久节点,顺序性临时节点
3.创建节点
create 节点名 数据: 持久性节点
create -e :临时性节点
create -s :顺序性节点
4.读写锁(分布式锁)
zookeeper的节点是唯一性的,我们可以创建一个临时顺序性节点(避免羊群效应,一次通知太多的节点),节点名称可以带有read或write再加上节点名称,节点数据可以使用客户端id,客户端访问时会先判断是否存在锁,不存在则设置锁,存在则进入等待,等线程执行完后可以删除该临时节点,其他线程就可以根据watcher监听重新获取锁
5.怎么保证主从状态同步
通过zab协议的恢复模式和广播模式来保证主从状态同步
6.通知机制
通知机制用于监听znode的变化,变化时会通知客户端,注册一次性的watcher来监听事件,watcher不能保证事务的顺序性
7.zookeeper的特点
zookeeper是个数据库,文件存储系统,提供了事务监督通知,zookeeper更适用与传统的分布式场景
RocketMq,RabbitMq,Kafka
1.各自的特点和区别
rabbitmq:多语言,多协议,高可用高并发,有消息跟踪,有友好的可视化界面,不支持二次开发
rocketmq:高可用,低延迟,支持事务,延迟消息,有消息追踪,有可视化界面,多语言多协议,所有数据持久化,不支持消息优先级
kafka:低延迟,高吞吐量,高性能分布式储存,缺少可视化界面,不支持延迟消息,消息追踪
mybatis
1.mybatis的延迟加载
延迟加载又叫懒加载,也叫按需加载,也就是说先加载主信息,需要的时候,再去根据推迟策略加载从信息(直接加载,侵入式延时加载,深度延时加载)
开启方式:设置lazyLoadingEnabled=true
MyBatis 延迟加载是通过动态代理实现的,当调用配直为延迟加载的属性方法时, 动态代
理的操作会被触发,这些额外的操作就是通过 MyBatis 的 SqlSessio口去执行嵌套 SQL 的 。
由于在和某些框架集成时, SqlSession 的生命周期交给了框架来管理,因此当对象超出
SqlSession 生命周期调用时,会由于链接关闭等问题而抛出异常 。
2.mybatis的二级缓存
一级缓存默认开启,基于sqlSession实现的,底层依旧属于hashmap结构
二级缓存需要手动开启,添加配置或是使用注解,是基于mapper文件的namespace的实现的,底层依旧属于hashmap结构
3.mybatis的执行器
简单执行器:这是默认的执行器类型,它每次执行都会创建一个Statement对象,并立即执行SQL语句。这种执行器不支持事务
重用执行器:当需要执行相同的SQL语句时,会直接使用缓存的Statement对象,而不是每次都创建新的对象。这种执行器也不支持事务
批处理执行器:这种执行器用于批量操作,可以一次执行多个SQL语句
4.查询大量数据避免内存溢出怎么处理
流式查询:建立长链接,利用服务端游标,每次读取一条加载一条
游标查询:通过fetchSize控制一次读取多少条
5.大量数据怎么排序
合理简历索引,创建索引时,索引已经帮忙排序了
6.mybatis怎么映射的
resultType:自动映射
resultMap:自定义映射
mysql
1.索引的结构和储存位置
b+树结构
叶子节点存放的是实际的行数据,而非叶子节点存放的是主键和页号
mysql会将索引存到磁盘上,但会将常用的索引存到内存中,有限查询内存再查询磁盘
2.聚簇索引和非聚簇索引的区别
聚簇索引的叶子节点储存的是数据行和主键值
非聚簇索引索引的叶子节点储存的是主键值和数据记录地址,查询需要回表(所有查询条件都命中索引时不会回表)
3.索引的类型
聚簇索引,非聚簇索引
覆盖索引(索引包含所有查询条件)
联合索引
唯一索引(保证数据的唯一性,主键id)
主键索引(表中的第一个索引)
全文索引(对文本内存进行提取)
4.索引失效的方式
联合索引不满足最左前缀法则,左模糊匹配,列运算,使用函数,类型转换,使用is not null,使用or,非驱动表使用orderby
5.explan后各属性意思
id:列数字越大越先执行
select_type:查询类型
table:表名
type:查询的结果类型(除了all外其他的都使用到了索引)
possible_keys:可能使用到的索引
key:真正使用到的索引
key_len:索引长度
rows:预估扫描的行数
6.mysql三范式
保证原子性,数据的每一列都是不可分割的原子数据项
实体属性必须完全依赖主关键字
任何非主属性不依赖其他非主属性
7.ACID是什么
原子性:要么全部完成要么全部失败
一致性:数据的完整性没有遭到破坏
隔离性:允许多个事务对数据进行读写
持久性:对数据的修改时永久的,不会丢失
8.mysql两种引擎的区别
innoDB:支持事务,行锁表锁,不会记录表的数据量,查询count时会扫描全表
myIASM:不支持事务,只支持表锁,会记录表的数据量
行锁:开销大,加锁慢,会出现死锁,锁冲突概率小,并发高
表锁:开销小,加锁块,不会死锁,锁冲突概率大,并发低
9.可以使用多少列创建索引
一个表最多给16个列建索引
10.如何优化distinct
根据业务场景合理使用orderby和内查询解决
11.now()和cruuent_date()的区别
now()返回的时间更详细包含了年月日时分秒微秒,cruuent_date只包含年月日
12.列对比运算符是什么
就是逻辑运算符(=,>,<,in,like之类的)
13.主键和候选键的区别
每个表必须有主键,且不能为空,候选键不一定存在,可以为多列组合,且可以为空
14.mysql有哪些不同的表格
事务安全型:BDB,InnoDB
非事务安全型:HEAP,ISAM,MERGE,MYISAM,MERGE
15.怎么保证分库时同一个用户数据落到同一个库
基于用户id进行分库
16.怎么实现主从数据库
在主服务器上,设置一个从数据库的账户,使用replication slave赋予权限
修改主数据的配置文件,开启binlog,设置server-id的值
停止主数据库的更新,备份主数据库数据
修改从数据库的配置文件,增加server-id指定复制的数据库
从服务器启动slave进程和show salve status验证
17.怎么实现分库分表
可以使用mycat,mybatis-sharding插件完成分表
18.怎么保证主从一致性
半同步复制:事务在主库写完binlog后,需要从库返回一个已接收,才能返回给客户端
数据库中间件:所有的读写都走中间件,记录所有路由到写库的key, 如果在主从同步的窗口内有读请求过来了,就需要将key上的读请求路由到主库访问
19.插件有哪些分表规则
按值的范围,按值的hash,按指定的值,自定义字段,按取模结果
线程
1.线程池参数
最大线程数,核心线程数,空闲线程存活时间,时间单位,工作队列,线程工厂,拒绝策略
新任务会优先进队列,队列满了就会创建新线程,当线程和队列都满了就会走拒绝策略
2.三个线程123,如何保证顺序执行
创建三个线程,分别调用方法,提供参数打印顺序(0,1,2)和打印的东西
提供公共参数打印次数,方法内部使用for循环,在循环内上锁,根据打印次数取余3来判断该由那个线程打印
private int time;// 控制打印次数
private int state;// 当前状态值:保证三个线程之间交替打印
public void print(String str, int targetNum) {
for (int i = 0; i < time; ) {
lock.lock();//上锁
//只有满足顺序条件的时候才打印 并且state++和i++
if (state % 3 == targetNum) {
state++;
i++;
System.out.print(str);
}
lock.unlock();//解锁
}
}
Thread A = new Thread(() -> {
th.print("A", 0);
});
Thread B = new Thread(() -> {
th.print("B", 1);
});
Thread C = new Thread(() -> {
th.print("C", 2);
});
B.start();
A.start();
C.start();
3.可见性和安全性的区别
可见性:线程对数据的操作可以被其他线程发现
安全性:多个现场交替执行时,不需要进行额外的同步操作,依旧能保证数据的正确性
4.原子性和一致性的区别
原子性:一起成功一起失败
一致性:数据操作的完整性
5.cpu数量和线程池数量的关系
cpu密集型的应用:线程池线程数=cpu线程数+1
io密集型应用:线程池线程数=cpu线程数*2+1
6.cas的机制
cas是jdk提供的非阻塞原子操作,是使用cmpxchg命令实现cpu独占的,他会对总线加锁并且只有一个线程能加锁,对比synchronized来说cas的排他时间更短
缺点:cas是乐观锁的一种实现,在竞争激烈的情况下容易造成cpu空转,浪费cpu性能
7.volatile的作用
变量修饰符,让其对线程保持修改可见性
容器
1.hashmap实现原理
会根据key的hash值计算取出对应下标进行储存,当hash值一致时会造成hash冲突,此时会根据equals判断是否重复,会将不重复的数据插入链表中(1.7头插法,1,8尾插法),当链表数据超过8时,会将链表转化为红黑树结构,hashmap默认储存容量是16,当超过初始因子(0.75)后,会进行扩容2倍
负载因子设计大了,则容易发生哈希冲突,设计小了,不能充分利用空间,0.75这个值是通过数学中的泊松分布计算出来的,可以达到一个最好的平衡
2.ConcurrentHashMap实现原理
1.7使用分段锁,将数据分为多段,每段都相当于hashmap,让元素自己管理自己的锁
1.8使用cas+synchronized
3.synchronizedMap实现原理
通过synchronized来保证只有一个线程对map进行操作
4.linkedHashMap怎么实现有序
hashmap+双向链表(记录插入顺序)
5.vectory底层实现原理
其中大部分的方法都被synchronized关键字所修饰
io
1.BIO和NIO的区别
bio是面向流的单向传输
nio是面向缓存的双向传输,通过通道和缓冲区来处理io
2.怎么实现多路复用
通过选择器监听通道事件,来轮询读写
网络
1.http和https
http链接简单,默认采用80端口,数据是明文传输
https采用ssl进行加密传输,默认端口443
2.mqtt
mqtt是一种轻量级协议,采用长链接保持通信,消息头和消息都很小,确保了高传输保证,吞吐量远远大于http
3.tcp怎么保证传输安全
校验和,序列号,确认应答,超时重传,连接管理,流量控制
4.osi七层模型
- 物理层:利用传输介质为数据链路层提供物理连接,实现比特流的透明传输。
- 数据链路层:负责建立和管理节点间的链路。
- 网络层:通过路由选择算法,为报文或分组通过通信子网选择最适当的路径。
- 传输层:向用户提供可靠的端到端的差错和流量控制,保证报文的正确传输。
- 会话层:向两个实体的表示层提供建立和使用连接的方法。
- 表示层:处理用户信息的表示问题,如编码、数据格式转换和加密解密等。
- 应用层:直接向用户提供服务,完成用户希望在网络上完成的各种工作。
5.session和cookie
session:服务器创建sessionid后会发送到客户端,客户端放到浏览器储存,之后请求都会带着sessionid进去确认
- 存储位置不同:session 存储在服务器端;cookie 存储在浏览器端。
- 安全性不同:cookie 安全性一般,在浏览器存储,可以被伪造和修改。
- 容量和个数限制:cookie 有容量限制,每个站点下的 cookie 也有个数限制。
- 存储的多样性:session 可以存储在 Redis 中、数据库中、应用程序中;而 cookie 只能存储在浏览器中。
6.分布式session怎么实现
- 将一台机器上的session,广播复制到集群其他机器上
- 强制将后续请求放在同一个机器上
- 将session存到分布式缓存集群中,用户访问时先从缓存中拿session
7.浏览器输入url后的执行流程
网页重定向,本地缓存,域名解析,建立tcp连接,浏览器发送http请求,服务端响应http请求,断开http连接,返回数据渲染页面
8.怎么保证网络请求的安全
token校验
ip黑名单,白名单
时间戳加密:客户端请求携带加密时间戳,服务端解密判断时间戳间隔
jvm
1.jvm组成
类加载器:装载class文件到方法区
运行时数据区:jvm内存
执行引擎:解释命令交给操作系统执行
本地库接口:与其他编程语言交互接口
2.类加载的流程
加载:将类转化为二级制字节流
验证:检查类的文件格式,元数据,字节码,符号引用
准备:为变量开辟空间,初始化
解析:将符号引用转化为直接引用
初始化:执行字节码文件,开始初始化方法
3.类加载器和双亲委派模型
启动类加载器,应用程序类加载器,拓展类加载器,其他类加载器
当需要进行类加载时,当前加载器会将请求交给父级去执行,父级继续向父级加载,直到父级无法加载时,才会在当前加载器进行加载
保证了java程序的稳定执行,避免重复加载
4.堆,栈,队列的区别
堆:二叉树结构,线程共享,空间大,用来存放对象
栈:线程私有,空间小,用来执行方法,先进后出
队列:先进先出
5.怎么判断对象是否能回收
引用计数器:对象被引用时计数器+1,被释放时-1,为0时可以被回收,不能解决循环依赖
可达性分析:从GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的
6.垃圾回收算法
- 标记-清除算法:标记无用对象,然后进行清除回收。缺点:效率不高,无法清除垃圾碎片。
- 标记-整理算法:标记无用对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。
- 复制算法:按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一半。
- 分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年代采用标记整理算法。
7.垃圾回收器
- Serial:最早的单线程串行垃圾回收器。
- Serial Old:Serial 垃圾回收器的老年版本
- ParNew:是 Serial 的多线程版本。
- CMS:一种以获得最短停顿时间为目标的收集器,非常适用 B/S 系统。
- G1:一种兼顾吞吐量和停顿时间的 GC 实现,是 JDK 9 以后的默认 GC 选项。
8.年轻代,老年代
分代回收器有两个分区:老生代和新生代,新生代默认的空间占比总空间的 1/3,老生代的默认占比是 2/3。
新生代使用的是复制算法,新生代里有 3 个分区:Eden、To Survivor、From Survivor,它们的默认占比是 8:1:1,它的执行流程如下:
- 把 Eden + From Survivor 存活的对象放入 To Survivor 区;
- 清空 Eden 和 From Survivor 分区;
- From Survivor 和 To Survivor 分区交换,From Survivor 变 To Survivor,To Survivor 变 From Survivor。
每次在 From Survivor 到 To Survivor 移动时都存活的对象,年龄就 +1,当年龄到达 15(默认配置是 15)时,升级为老生代。大对象也会直接进入老生代,一般使用标记整理的执行算法。
9.jvm调优参数
1、尽可能让对象在新生代里分配和回收,避免对象频繁进入老年代导致老年代频繁垃圾回收;
2、给系统充足的内存空间,避免新生代频繁的垃圾回收;
3、指定合适的垃圾收集器;
10.cpu100%怎么排查
通过top名称查看pid和线程号
通过命令输出进程的线程文件
分布式
1.分布式事务
2.怎么实现分布式锁
使用数据的乐观锁,悲观锁实现
使用redis分布式锁
使用zookeeper的临时性顺序节点
3.分布式接口的幂等性
乐观锁
数据库主键
4.分布式锁的限流
使用redis的令牌桶算法,将token list存到redis中,设置令牌最大数量,判断redis中获取令牌的token数据,超出最大值直接拒绝访问,否则重试设置令牌数量及过期时间
使用reids的计数器算法,记录ip的请求次数,设置过期时间,超过阈值直接拒绝访问
数据结构
1.二叉树
每个节点最多只有左右两个节点
2.红黑树
是一种平衡二叉查找树,减小了二叉树的深度,提高了查找效率,极端情况下可能会蜕变为链表
根节点是黑的,所有的叶子都是黑的空节点,每个红节点必须有两个黑色的子节点
3.b树和b+树
4.散列表
5.二叉查找树
任意节点的左子树不为空,且左子树上任意节点小于根节点
任意节点的右子树不为空,且右子树上任意节点小于根节点
算法
1.冒泡排序
当数组中前一个元素大于后一个元素,交换,使得较小的元素移动到前面,较大的移动到后面,重复对比和交换的过程
//冒泡排序
public static void bubbleSort(int[] array){
for(int i = 0; i < array.length-1; i++ ){
for(int j = 0 ; j < array.length-1-i; j++){
if(array[j] > array[j+1]){
swap(array,j,j+1);
}
}
}
}
2.选择排序
每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置
//选择排序--直接选择排序
public static void selectSort(int[] array){
// 外层循环表示需要走的内层循环趟数
// 每走一次内层循环,就有一个元素(当前最小值)放在正确位置
for(int i = 0; i< array.length-1; i++){
int min = i;
for(int j = i + 1;j < array.length;j++){
if(array[min] > array[j]){
min = j;
}
}
// 此时min就保存了最小值索引,交换i和min的元素即可
swap(array,i,min);
}
}