一:Java集合
1.Java 集合框架的基础接口有哪些?
- Collection ,为集合层级的根接口。一个集合代表一组对象,这些对象即为它的元素。java平台不提供这个接口的任何直接实现。
- Set
- HashSet :无序,唯一,基于HashMap 实现的,底层采用HashMap 来保存元素。
- LinkedHashSet : 继承自HashSet,并且底部是通过LinkedHashSet来实现的。
- TreeSet : 有序,唯一,红黑树(自平衡的排序二叉树)
- List,有序,不唯一。List更像长度变换的数组。
- ArrayList :Object数组。
- Vector:Object数组。
- LinkedList:双向链表(JDK1.6之前为循环链表,JDK7取消了循环)
- Map,是一个将key映射到value的对象。key唯一,value不唯一。
- HashMap
- JDK8之前,HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解诀哈希冲突而存在的(“拉链法”解决冲突)。
- JDK8以后,在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。
- LinkedHashMap:继承自HashMap,所以它的底层仍然是基于拉链式散列结构既由数组和链表或红黑树组成。
- Hashtable : 数组+链表组成的,彤HashMap 1.8版本之前的一样。
- TreeMap :红黑树(自平衡的排序二叉树)
- 一些其它的接口有Queue、Dequeue、SortedSet、SortedMap和Listltertor。
2.为何 Collection 不从 Cloneable 和 Serializable 接口继承?
- Collection 接口指定一组对象,对象即为它的元素。
- 如何维护这些元素由Collection 的具体实现决定。参考List和set的特性。
- 很多 Collection 实现有一个公有的clone 方法。然而,把它放到集合的所有实现中也是没有意义的。这是因为 Collection 是一个抽象表现,重要的是实现。
- 当与具体实现打交道的时候,克隆或序列化的语义和含义才发挥作用。特定的实现应该决定它是否可以被克隆和序列化。
3.为何 Map 接口不继承 Collection 接口?
- Map和List、set 不同,Map放的是键值对,list、set放的是一个个的对象,说到底是因为数据结构不同,操作就不一样,所以接口是分开的。还是接口分离原则。
- 如果Map继承了Collection 接口,那么元素去哪儿? Map 包含 key-value(键值对)对,它提供抽取key或value列表集合的方法,但是它不适合 一组对象 规范。
4.Collection 和 Collections 的区别?
- Collection ,是集合类的上级接口,继承与他的接口主要有 Set 和List 。
- Collections ,是针对集合类的一个工具类,它提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。
5.集合框架里实现的通用算法有哪些?
Java 集合框架提供常用的算法实现,比如排序和搜索。
Collections类包含这些方法实现。大部分算法是操作 List 的,但一部分对所有类型的集合都是可用的。部分算法有排序、搜索、混编、最大最小值
6.什么是迭代器(Iterator)?
Iterator 接口,提供了很多对集合元素进行迭代的方法。
Enumeration 和 Iterator 接口有什么不同?
- Enumeration 跟 Iterator 相比较快两倍,而且占用更少的内存。
- 但是,Iterator 相对于 Enumeration 更安全,因为其他线程不能修改当前迭代器遍历的集合对象。
7.Iterator 和 ListIterator 的区别是什么?
- Iterator 可用来遍历 Set 和 List 集合,但是 ListIterator 只能用来遍历 List。
- Iterator 对集合只能是前向遍历,ListIterator 既可以前向也可以后向。
- ListIterator 实现了 Iterator 接口,并包含其他的功能。比如:增加元素,替换元素,获取前一个和后一个元素的索引等等。
8.如何删除 List 中的某个元素?
- 方式一,使用 Iterator ,顺序向下,如果找到元素,则使用 remove 方法进行移除。
- 方式二,倒序遍历 List ,如果找到元素,则使用 remove 方法进行移除。
9.如何对 Object 的 List 排序?
- 对
Object[]
数组进行排序时,我们可以用Arrays#sort(...)
方法。- 对
List<Object>
数组进行排序时,我们可以用Collections#sort(...)
方法。
二:多线程面试题
1、 什么是线程?
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。
2、线程和进程有什么区别?
一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。
一个进程可以有多个线程。
3、 如何在Java中实现线程?
(1).继承Thread类实现多线程
继承Thread类,然后重写run方法.(由于Java单继承的特性,这种方式用的比较少)
2).实现Runnable()接口定制执行目标(target)类,实现其run()方法
推荐此方式。两个特点:
a.覆写Runnable接口实现多线程可以避免单继承局限
b.实现Runnable()可以更好的体现共享的概念
c.当执行目标类实现Runnable接口,此时执行目标(target)类和Thread是代理模式(子类负责真是业务的操作,thread负责资源调度与线程创建辅助真实业务。
.3.实现Callable接口创建多线程(JDK1.5)
a.执行目标核心方法叫call()方法
b.有返回值
4.如何避免死锁?
Java多线程中的死锁
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件:
- 互斥条件:一个资源每次只能被一个进程使用。
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。
5. 怎么检测一个线程是否拥有锁?
在java.lang.Thread中有一个方法叫holdsLock(),它返回true如果当且仅当当前线程拥有某个具体对象的锁。
6. 线程池的七个参数
下面是ThreadPoolExecutor类的构造方法源码,其他创建线程池的方法最终都会导向这个构造方法,共有7个参数:corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler。
corePoolSize:核心线程数
maximumPoolSize:最大线程数
keepAliveTime:空闲线程存活时间
unit:时间单位
workQueue:工作队列
threadFactory:线程工厂
handler:拒绝策略
三. redis 面试题
1.什么是redis
Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API的非关系型数据库。
2.Redis支持的数据类型?
String字符串 、Hash(哈希)、List(列表)、set(集合)、zset(有序集合)
3.什么是Redis持久化?Redis有哪几种持久化方式?优缺点是什么?
持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。
Redis 提供了两种持久化方式:RDB(默认) 和AOF
RDB:
rdb是Redis DataBase缩写
功能核心函数rdbSave(生成RDB文件)和rdbLoad(从文件加载内存)两个函数
AOF:
Aof是Append-only file缩写
每当执行服务器(定时)任务或者函数时flushAppendOnlyFile 函数都会被调用, 这个函数执行以下两个工作
aof写入保存:
WRITE:根据条件,将 aof_buf 中的缓存写入到 AOF 文件
SAVE:根据条件,调用 fsync 或 fdatasync 函数,将 AOF 文件保存到磁盘中。
存储结构:
内容是redis通讯协议(RESP )格式的命令文本存储。
比较:
1、aof文件比rdb更新频率高,优先使用aof还原数据。
2、aof比rdb更安全也更大
3、rdb性能比aof好
4、如果两个都配了优先加载AOF
刚刚上面你有提到redis通讯协议(RESP ),能解释下什么是RESP?有什么特点?(可以看到很多面试其实都是连环炮,面试官其实在等着你回答到这个点,如果你答上了对你的评价就又加了一分)
RESP 是redis客户端和服务端之前使用的一种通讯协议;
RESP 的特点:实现简单、快速解析、可读性好
Redis 有哪些架构模式?讲讲各自的特点
单机版
特点:简单
问题:
1、内存容量有限 2、处理能力有限 3、无法高可用。
主从复制
Redis 的复制(replication)功能允许用户根据一个 Redis 服务器来创建任意多个该服务器的复制品,其中被复制的服务器为主服务器(master),而通过复制创建出来的服务器复制品则为从服务器(slave)。 只要主从服务器之间的网络连接正常,主从服务器两者会具有相同的数据,主服务器就会一直将发生在自己身上的数据更新同步 给从服务器,从而一直保证主从服务器的数据相同。
特点:
1、master/slave 角色
2、master/slave 数据相同
3、降低 master 读压力在转交从库
问题:
无法保证高可用
没有解决 master 写的压力
哨兵
Redis sentinel 是一个分布式系统中监控 redis 主从服务器,并在主服务器下线时自动进行故障转移。其中三个特性:
监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作。
特点:
1、保证高可用
2、监控各个节点
3、自动故障迁移
缺点:主从模式,切换需要时间丢数据
没有解决 master 写的压力
集群(proxy 型):
Twemproxy 是一个 Twitter 开源的一个 redis 和 memcache 快速/轻量级代理服务器; Twemproxy 是一个快速的单线程代理程序,支持 Memcached ASCII 协议和 redis 协议。
特点:1、多种 hash 算法:MD5、CRC16、CRC32、CRC32a、hsieh、murmur、Jenkins
2、支持失败节点自动删除
3、后端 Sharding 分片逻辑对业务透明,业务方的读写方式和操作单个 Redis 一致
缺点:增加了新的 proxy,需要维护其高可用。
failover 逻辑需要自己实现,其本身不能支持故障的自动转移可扩展性差,进行扩缩容都需要手动干预
集群(直连型):
从redis 3.0之后版本支持redis-cluster集群,Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。
特点:
1、无中心架构(不存在哪个节点影响性能瓶颈),少了 proxy 层。
2、数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布。
3、可扩展性,可线性扩展到 1000 个节点,节点可动态添加或删除。
4、高可用性,部分节点不可用时,集群仍可用。通过增加 Slave 做备份数据副本
5、实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成 Slave到 Master 的角色提升。
缺点:
1、资源隔离性较差,容易出现相互影响的情况。
2、数据通过异步复制,不保证数据的强一致性
使用过Redis分布式锁么,它是怎么实现的?
先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?
set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的!
1).穿透,击穿,雪崩的解决方案;
*缓存雪崩:短时间内,缓存中的key集中过期;
解决方案:
1 更多的静态化页面;
- 构建多级缓存架构--> Nginx缓存+redis缓存+ehcache缓存;
- 不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀;
- 检测Mysql严重耗时业务进行优化-->对数据库的瓶颈排查:例如超时查询,耗时较高事务;
- 灾难预警机制-->监控redis服务器性能指标 CPU占用,CPU使用率 内存容量 查询平均响应时间 线程数
- 限流,降级-->短时间范围内牺牲一些客户体验,限制一部分请求访问,降低应用服务器压力,待业务低速运转后再逐步放开访问
落地实践:
- LRU与LFU切换
- 数据有效期策略调整
- 超热数据使用永久key
- 定期维护(自动+人工)
*缓存击穿:单个key高热数据,key过期
解决方案:
- 预先设定:以电商为例,购物节期间设置主打产品key过期时间
- 现场调控:监控访问量,对自然流量激增的数据延长过期时间或设置为永久key
- 后台刷新数据:启动定时任务,高峰来临之前,刷新数据有效期,确保不丢失
- 二级缓存:设置不同的失效时间,保障不会被同时淘汰就行
- 加锁:分布式锁,防止被击穿,但是要注意也是性能瓶颈,慎用!
*缓存穿透:Redis中key大面积出现未命中,出现非正常的URL访问
解决方案:
- 缓存null
- 白名单策略,使用布隆过滤器
- 实施监控
- Key加密
四. MongoDB
1.什么是MongoDB
MongoDB是一个文档数据库,提供好的性能,领先的非关系型数据库。采用BSON存储文档数据。 BSON()是一种类json的一种二进制形式的存储格式,简称Binary JSON. 相对于json多了date类型和二进制数组。
2.MongoDB的优势有哪些
- 面向文档的存储:以 JSON 格式的文档保存数据。
- 任何属性都可以建立索引。
- 复制以及高可扩展性。
- 自动分片。
- 丰富的查询功能。
- 快速的即时更新。
3 什么是数据库
数据库可以看成是一个电子化的文件柜,用户可以对文件中的数据运行新增、检索、更新、删除等操作。
4.什么是集合(表)
集合就是一组 MongoDB 文档。它相当于关系型数据库(RDBMS)中的表这种概念。集合位于单独的一个数据库中。 一个集合内的多个文档可以有多个不同的字段。一般来说,集合中的文档都有着相同或相关的目的。
5 什么是文档(记录)
文档由一组key value组成。文档是动态模式,这意味着同一集合里的文档不需要有相同的字段和结构。在关系型 数据库中table中的每一条记录相当于MongoDB中的一个文
6 MongoDB和关系型数据库术语对比图
7.什么是非关系型数据库
非关系型数据库的显著特点是不使用SQL作为查询语言,数据存储不需要特定的表格模式。
8 为什么用MOngoDB?
- 架构简单
- 没有复杂的连接
- 深度查询能力,MongoDB支持动态查询。
- 容易调试
- 容易扩展
- 不需要转化/映射应用对象到数据库对象
- 使用内部内存作为存储工作区,以便更快的存取数据。
9 在哪些场景使用MongoDB
- 大数据
- 内容管理系统
- 移动端Apps
- 数据管理
五.消息中间件 面试题
1).消息丢失,幂等性消费的解决方案;
消息丢失:交换机和消息队列进行持久化 ack应答机制 如果是rabbitmq 可以用confirm机制
为什么会使用kafka时出现消息重复消费的问题?
答案:消费者准备提交offset,但还没有提交的时候,消费者进程被重启了(比如说宕机,或者kill-9),那此时offset还没有提交.kafka不知道你消费了offset=xxx的那条数据.消费者一旦重启,数据1和数据2又发送过来,对于消费者来说,数据1和数据2在数据库消费了两次.
如何保证重复消费的幂等性?
答案:1. 如果你拿个数据要写库,你先根据主键id查一下,如这数据都有了,你就别插入了,update一下.
- 如果你拿个数据是要更新表里的字段,直接update就好,幂等的.
- 基于数据库的唯一性索引.因为有唯一性索引了,所以重复数据只会插入报错,不会导致数据库中出现重复的数据.
- 如果你是写redis,那就没问题,每次都是set,天然幂等.
- 如果不是上面的场景,那想的稍微复杂一点,需要生产者在发送消费的时候里面加一个全局性的唯一ID(UUID或者雪花算法),类似于订单ID之间的东西,先根据这个ID去redis中去查一下,之前消费过吗?如果没有消费过你就处理,然后把这个唯一性的ID写Redis.如果消费过了,就不处理了.
- .mq应用的场景;
应用解耦 削峰填谷 限流 异步通信
- .mq底层原理;
kafka
消息系统的作用
应该大部份小伙伴都清楚,用机油装箱举个例子
所以消息系统就是如上图我们所说的仓库,能在中间过程作为缓存,并且实现解耦合的作用。
引入一个场景,我们知道中国移动,中国联通,中国电信的日志处理,是交给外包去做大数据分析的,假设现在它们的日志都交给了你做的系统去做用户画像分析。
按照刚刚前面提到的消息系统的作用,我们知道了消息系统其实就是一个模拟缓存 ,且仅仅是起到了缓存的作用 而并不是真正的缓存,数据仍然是存储在磁盘上面而不是内存。
1.Topic 主题
kafka学习了数据库里面的设计,在里面设计了topic(主题),这个东西类似于关系型数据库的表
此时我需要获取中国移动的数据,那就直接监听TopicA即可
2.Partition 分区
kafka还有一个概念叫Partition(分区),分区具体在服务器上面表现起初就是一个目录,一个主题下面有多个分区,这些分区会存储到不同的服务器上面,或者说,其实就是在不同的主机上建了不同的目录。
这些分区主要的信息就存在了.log文件里面。跟数据库里面的分区差不多,是为了提高性能。
至于为什么提高了性能,很简单,多个分区多个线程,多个线程并行处理肯定会比单线程好得多
Topic和partition像是HBASE里的table和region的概念,table只是一个逻辑上的概念,真正存储数据的是region,这些region会分布式地存储在各个服务器上面,对应于kafka,也是一样,Topic也是逻辑概念 ,而partition就是分布式存储单元。这个设计是保证了海量数据处理的基础。
我们可以对比一下,如果HDFS没有block的设计,一个100T的文件也只能单独放在一个服务器上面,那就直接占满整个服务器了,引入block后,大文件可以分散存储在不同的服务器上。
注意:1.分区会有单点故障问题,所以我们会为每个分区设置副本数
2.分区的编号是从0开始的
3.Producer - 生产者
往消息系统里面发送数据的就是生产者
4.Consumer - 消费者
从kafka里读取数据的就是消费者
5.Message - 消息
kafka里面的我们处理的数据叫做消息
二、kafka的集群架构
创建一个TopicA的主题,3个分区分别存储在不同的服务器,也就是broker下面。Topic是一个逻辑上的概念 ,并不能直接在图中把Topic的相关单元画出
需要注意:kafka在0.8版本以前是没有副本机制的,所以在面对服务器宕机的突发情况时会丢失数据,所以尽量避免使用这个版本之前的kafka
Replica - 副本
kafka中的partition为了保证数据安全,所以每个partition可以设置多个副本。
此时我们对分区0,1,2分别设置3个副本(其实设置两个副本是比较合适的)
而且其实每个副本都是有角色之分的,它们会选取一个副本作为leader,而其余的作为follower,我们的生产者在发送数据的时候,是直接发送到leader partition里面 ,然后follower partition会去leader那里自行同步数据,消费者消费数据的时候,也是从leader那去消费数据的 。
Consumer Group - 消费者组
我们在消费数据时会在代码里面指定一个group.id,这个id代表的是消费组的名字,而且这个group.id就算不设置,系统也会默认设置
conf.setProperty("group.id","tellYourDream")
我们所熟知的一些消息系统一般来说会这样设计,就是只要有一个消费者去消费了消息系统里面的数据,那么其余所有的消费者都不能再去消费这个数据。可是kafka并不是这样,比如现在consumerA去消费了一个topicA里面的数据。
consumerA:
group.id = a
consumerB:
group.id = a
consumerC:
group.id = b
consumerD:
group.id = b
再让consumerB也去消费TopicA的数据,它是消费不到了,但是我们在consumerC中重新指定一个另外的group.id,consumerC是可以消费到topicA的数据的。而consumerD也是消费不到的,所以在kafka中,不同组可有唯一的一个消费者去消费同一主题的数据 。
所以消费者组就是让多个消费者并行消费信息而存在的,而且它们不会消费到同一个消息,如下,consumerA,B,C是不会互相干扰的
consumer group:a
consumerA
consumerB
consumerC如图,因为前面提到过了消费者会直接和leader建立联系,所以它们分别消费了三个leader,所以一个分区不会让消费者组里面的多个消费者去消费 ,但是在消费者不饱和的情况下,一个消费者是可以去消费多个分区的数据的 。
Controller
熟知一个规律:在大数据分布式文件系统里面,95%的都是主从式的架构,个别是对等式的架构,比如ElasticSearch。
kafka也是主从式的架构,主节点就叫controller,其余的为从节点,controller是需要和zookeeper进行配合管理整个kafka集群。
kafka和zookeeper如何配合工作
kafka严重依赖于zookeeper集群(所以之前的zookeeper文章还是有点用的)。所有的broker在启动的时候都会往zookeeper进行注册,目的就是选举出一个controller,这个选举过程非常简单粗暴,就是一个谁先谁当的过程,不涉及什么算法问题。
那成为controller之后要做啥呢,它会监听zookeeper里面的多个目录。
例如有一个目录/brokers/,其他从节点往这个目录上注册(就是往这个目录上创建属于自己的子目录而已) 自己,这时命名规则一般是它们的id编号,比如/brokers/0,1,2
注册时各个节点必定会暴露自己的主机名,端口号等等的信息,此时controller就要去读取注册上来的从节点的数据(通过监听机制),生成集群的元数据信息,之后把这些信息都分发给其他的服务器,让其他服务器能感知到集群中其它成员的存在 。
此时模拟一个场景,我们创建一个主题(其实就是在zookeeper上/topics/topicA这样创建一个目录而已),kafka会把分区方案生成在这个目录中,此时controller就监听到了这一改变,它会去同步这个目录的元信息,然后同样下放给它的从节点,通过这个方法让整个集群都得知这个分区方案,此时从节点就各自创建好目录等待创建分区副本即可。这也是整个集群的管理机制。
1.Kafka性能好在什么地方?
① 顺序写
操作系统每次从磁盘读写数据的时候,需要先寻址,也就是先要找到数据在磁盘上的物理位置,然后再进行数据读写,如果是机械硬盘,寻址就需要较长的时间。
kafka的设计中,数据其实是存储在磁盘上面,一般来说,会把数据存储在内存上面性能才会好。但是kafka用的是顺序写,追加数据是追加到末尾,磁盘顺序写的性能极高,在磁盘个数一定,转数达到一定的情况下,基本和内存速度一致
随机写的话是在文件的某个位置修改数据,性能会较低。
② 零拷贝
先来看看非零拷贝的情况
可以看到数据的拷贝从内存拷贝到kafka服务进程那块,又拷贝到socket缓存那块,整个过程耗费的时间比较高,kafka利用了Linux的sendFile技术(NIO),省去了进程切换和一次数据拷贝,让性能变得更好。
六.SpringMVC面试题
1、什么是Spring MVC?简单介绍下你对Spring MVC的理解?
Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把模型-视图-控制器分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。
2、Spring MVC的优点
(1)可以支持各种视图技术,而不仅仅局限于JSP;
(2)与Spring框架集成(如IoC容器、AOP等);
(3)清晰的角色分配:前端控制器(dispatcherServlet) , 请求到处理器映射(handlerMapping), 处理器适配器(HandlerAdapter), 视图解析器(ViewResolver)。
(4) 支持各种请求资源的映射策略。
3、Spring MVC的主要组件?
(1)前端控制器 DispatcherServlet(不需要程序员开发)
作用:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。
(2)处理器映射器HandlerMapping(不需要程序员开发)
作用:根据请求的URL来查找Handler
(3)处理器适配器HandlerAdapter
注意:在编写Handler的时候要按照HandlerAdapter要求的规则去编写,这样适配器HandlerAdapter才可以正确的去执行Handler。
(4)处理器Handler(需要程序员开发)
(5)视图解析器 ViewResolver(不需要程序员开发)
作用:进行视图的解析,根据视图逻辑名解析成真正的视图(view)
(6)视图View(需要程序员开发jsp)
View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等等)
4、什么是DispatcherServlet
Spring的MVC框架是围绕DispatcherServlet来设计的,它用来处理所有的HTTP请求和响应。
5、什么是Spring MVC框架的控制器?
控制器提供一个访问应用程序的行为,此行为通常通过服务接口实现。控制器解析用户输入并将其转换为一个由视图呈现给用户的模型。Spring用一个非常抽象的方式实现了一个控制层,允许用户创建多种用途的控制器。
6、Spring MVC的控制器是不是单例模式,如果是,有什么问题,怎么解决?
答:是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写字段。
7、请描述Spring MVC的工作流程?描述一下 DispatcherServlet 的工作流程?
(1)用户发送请求至前端控制器DispatcherServlet;
(2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
(3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
(4)DispatcherServlet 调用 HandlerAdapter处理器适配器;
(5)HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
(6)Handler执行完成返回ModelAndView;
(7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
(8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
(9)ViewResolver解析后返回具体View;
(10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
(11)DispatcherServlet响应用户。
8、MVC是什么?MVC设计模式的好处有哪些
mvc是一种设计模式(设计模式就是日常开发中编写代码的一种好的方法和经验的总结)。模型(model)-视图(view)-控制器(controller),三层架构的设计模式。用于实现前端页面的展现与后端业务数据处理的分离。
mvc设计模式的好处
1.分层设计,实现了业务系统各个组件之间的解耦,有利于业务系统的可扩展性,可维护性。
2.有利于系统的并行开发,提升开发效率。
9、注解原理是什么
注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象。通过代理对象调用自定义注解的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。
10、Spring MVC常用的注解有哪些?
@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。
@RequestBody:注解实现接收http请求的json数据,将json转换为java对象。
@ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。
11、SpingMvc中的控制器的注解一般用哪个,有没有别的注解可以替代?
答:一般用@Controller注解,也可以使用@RestController,@RestController注解相当于@ResponseBody + @Controller,表示是表现层,除此之外,一般不用别的注解代替。
12、Spring MVC的异常处理?
答:可以将异常抛给Spring框架,由Spring框架来处理;我们只需要配置简单的异常处理器,在异常处理器中添视图页面即可。
13、如果在拦截请求中,我想拦截get方式提交的方法,怎么配置
答:可以在@RequestMapping注解里面加上method=RequestMethod.GET。
14、怎样在方法里面得到Request,或者Session?
答:直接在方法的形参中声明request,Spring MVC就自动把request对象传入。
15、如果想在拦截的方法里面得到从前台传入的参数,怎么得到?
答:直接在形参里面声明这个参数就可以,但必须名字和传过来的参数一样。
16、如果前台有很多个参数传入,并且这些参数都是一个对象的,那么怎么样快速得到这个对象?
答:直接在方法中声明这个对象,Spring MVC就自动会把属性赋值到这个对象里面。
17、Spring MVC中函数的返回值是什么?
答:返回值可以有很多类型,有String, ModelAndView。ModelAndView类把视图和数据都合并的一起的,但一般用String比较好。
18、Spring MVC用什么对象从后台向前台传递数据的?
答:通过ModelMap对象,可以在这个对象里面调用put方法,把对象加到里面,前台就可以通过el表达式拿到。
19、怎么样把ModelMap里面的数据放入Session里面?
答:可以在类上面加上@SessionAttributes注解,里面包含的字符串就是要放入session里面的key。
20、Spring MVC里面拦截器是怎么写的
有两种写法,一种是实现HandlerInterceptor接口,另外一种是继承适配器类,接着在接口方法当中,实现处理逻辑;然后在Spring MVC的配置文件中配置拦截器即可:
1
2
3
4
5
6
7
8
9
10
<!-- 配置Spring MVC的拦截器 -->
<mvc:interceptors>
<!-- 配置一个拦截器的Bean就可以了 默认是对所有请求都拦截 -->
<bean id=
"myInterceptor"
class
=
"com.zwp.action.MyHandlerInterceptor"
></bean>
<!-- 只针对部分请求拦截 -->
<mvc:interceptor>
<mvc:mapping path=
"/modelMap.do"
/>
<bean
class
=
"com.zwp.action.MyHandlerInterceptorAdapter"
/>
</mvc:interceptor>
</mvc:interceptors>
七、Mybatis面试题
1.MyBatis是什么?
MyBatis 是一款优秀的持久层框架,一个半 ORM(对象关系映射)框架,它支持定制化 SQL、存储过程以及高级映射。
什么是ROM?
ORM(Object Relational Mapping),对象关系映射,是一种为解决关系型数据库数据与简单Java对象(POJO)的映射关系的技术。简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系型数据库中
2.为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?
Hibernate属于全自动ORM映射工具,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。
而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射工具。
3.传统JDBC开发存在的问题
1.频繁创建数据库连接对象、释放,容易造成系统资源浪费,影响系统性能。可以使用连接池解决这个问题。但是使用jdbc需要自己实现连接池。
2.sql语句定义、参数设置、结果集处理存在硬编码。实际项目中sql语句变化的可能性较大,一旦发生变化,需要修改java代码,系统需要重新编译,重新发布。不好维护。
3.使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
4.结果集处理存在重复代码,处理麻烦。如果可以映射成Java对象会比较方便。
JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?
1、数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。
解决:在mybatis-config.xml中配置数据链接池,使用连接池管理数据库连接。
2、Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
3、向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
解决:Mybatis自动将java对象映射至sql语句。
4、对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
解决:Mybatis自动将sql执行结果映射至java对象。
Mybatis优缺点
与传统的数据库访问技术相比,ORM有以下优点:
1.基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用
2.与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接
3.很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)
4.提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护
5.能够与Spring很好的集成
缺点
1.SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求
2.SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库
MyBatis框架适用场景
1.MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案。
2.对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis将是不错的选择。
Hibernate 和 MyBatis 的区别
相同点
都是对jdbc的封装,都是持久层的框架,都用于dao层的开发。
不同点
映射关系:
MyBatis 是一个半自动映射的框架,配置Java对象与sql语句执行结果的对应关系,多表关联关系配置简单
Hibernate 是一个全表映射的框架,配置Java对象与数据库表的对应关系,多表关联关系配置复杂
总结
MyBatis 是一个小巧、方便、高效、简单、直接、半自动化的持久层框架,
Hibernate 是一个强大、方便、高效、复杂、间接、全自动化的持久层框架。
MyBatis编程步骤是什么样的?
1、 创建SqlSessionFactory
2、 通过SqlSessionFactory创建SqlSession
3、 通过sqlsession执行数据库操作
4、 调用session.commit()提交事务
5、 调用session.close()关闭会话
Mybatis Plus面试题
MyBatis Plus简介?
MyBatis-Plus是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
Mybatis和Mybatis-plus的区别
区别一
如果Mybatis Plus是扳手,那Mybatis Generator就是生产扳手的工厂。
区别二
Mybatis-Plus是一个Mybatis的增强工具,它在Mybatis的基础上做了增强,却不做改变。我们在使用Mybatis-Plus之后既可以使用Mybatis-Plus的特有功能,又能够正常使用Mybatis的原生功能。
八.Spring 面试题
1.谈谈你对spring的理解
Spring框架是一个轻量级的开源框架,是核心容器、数据访问与集成、AOP、Web、消息、测试六个模块的集成,主要是为了简化企业级应用的后台开发,降低耦合性。
2.spring的特点
- 轻量
- 控制反转(IOC)
- 面向切面编程(AOP)
- 容器
- MVC框架
- 事务管理
- 异常处理
3.spring的优缺点
优点
- 方便解耦,简化开发
- 可以将对象的创建和依赖关系的维护交给Spring管理。
- 提供面向切面编程(AOP),可以方便的实现对程序进行权限拦截、运行监控等功能。
- 声明式事务的支持
- 只需要通过配置就可以完成对事务的管理,而无需手动编程。
- 降低 JavaEE API 的使用难度
缺点:
Spring明明一个很轻量级的框架,却给人感觉大而全
Spring依赖反射,反射影响性能
使用门槛过高,入门Spring需要较长时间
4. Spring由哪些模块组成?
Spring 总共有 20 个模块, 由 1300 多个不同的文件构成。 而这些组件被分别整合在核心容器 、 AOP和设备支持 、数据访问与集成 、 Web、 消息 、 测试 6 个模块中
5. 解释AOP模块
AOP 模块用于 Spring 应用做面向切面的开发,很多支持由 AOP 联盟提供,这样就确保了 Spring和其他 AOP 框架的共通性。AOP模块将元数据编程引入Spring。
6. 解释JDBC抽象和DAO模块
通过使用JDBC抽象和 DAO 模块,保证数据库代码的简洁,并能避免数据库资源错误关闭导致的问题, 它在各种不同的数据库的错误信息之上,提供了一个统一的异常访问层。它还利用 Spring 的 AOP 模块给 Spring 应用中的对象提供事务管理服务。
7.解释对象/关系映射集成(ORM)模块
Spring 通过提供ORM模块,支持我们直接在JDBC 之上使用一个对象/关系映射(ORM)工具。
Spring 支持集成主流的 ORM 框架。
Spring 的事务管理同样支持主流的 ORM 框架及 JDBC。
8. 解释WEB模块
Spring 的 WEB 模块是构建在 application context 模块基础之上,提供一个适合 web 应用的上下文。
9. Spring配置文件
Spring 配置文件是个XML文件,这个文件包含了类信息,描述了如何配置它们,以及如何相互调用。
10.什么是Spring IoC 容器。
控制反转即IoC ,它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现组件对象的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。Spring IOC 负责创建对象,管理对象,装配对象,配置对象,并且管理这些对象的整个生命周期。
11.控制反转(IoC)有什么作用
管理对象的创建和依赖关系的维护。
方便解耦,由容器去维护具体的对象
12.控制反转(IoC)的优点是什么?
把应用的代码量降到最低。
13. Spring IoC 的实现机制
Spring 中的 IoC 的实现原理就是工厂模式加反射机制。
14. Spring 的 IoC支持哪些功能
依赖注入
依赖检查
自动装配
支持集合
指定初始化方法和销毁方法
支持回调某些方法
一个 Spring 的应用看起来像什么?
一个定义了一些功能的接口 。
Spring AOP
Spring 的 XML 配置文件
使用以上功能的客户端程序
15.什么是Spring的依赖注入(DI)?
依赖注入是组件之间的依赖关系,由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例化,并注入到应用系统中的各个关联的组件之中。组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系。
16.有哪些不同类型的依赖注入方式,推荐使用哪种?
构造器注入、接口注入和 Setter 方法注入。最好的解决方案是用构造器参数实现强制依赖, setter 方法实现可选依赖。
17.什么是事务?
事务你可以去看概念,我给你说下简单理解。你去斗鱼送礼物,扣了你的鱼丸给主播送了礼物,这俩操作必须是绑定在一起的,不然单个任何一个完成了另外一个没完成都会出问题。对到数据库的操作就是,你花钱,买了礼物,礼物送出去。前面两个步骤就是一个事物,花钱买-礼物发到你库存。然后这东西肯定要写到库里。这么说明白了吧,同样送礼物这个,从你的库存拿走,送给主播,也必须是一致的,必须一起完成。面试时候就照着这个意思大概的发挥吧。