SpringMVC执行流程
1.用户发送请求至前端控制器DispatcherServlet
2.DispatcherServlet收到请求调用处理器映射器HandlerMapping
3.处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet
4.DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
5.执行处理器Handler(Controller,也叫页面控制器)
6.Handler执行完成返回ModelAndView
7.HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
8.DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9.ViewReslover解析后返回具体View
10.DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)
11.DispatcherServlet响应用户
SpringMVC执行流程图解
mybatis面试题
什么是mybatis
- Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,加载驱动、创建连接、创建statement等繁杂的过程,开发者开发时只需要关注如何编写SQL语句,可以严格控制sql执行性能,灵活度高。
- 作为一个半ORM框架,MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
称Mybatis是半自动ORM映射工具,是因为在查询关联对象或关联集合对象时,需要手动编写sql来完成。不像Hibernate这种全自动ORM映射工具,Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取。
- 通过xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过java对象和 statement中sql的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回。(从执行sql到返回result的过程)。
- 由于MyBatis专注于SQL本身,灵活度高,所以比较适合对性能的要求很高,或者需求变化较多的项目,如互联网项目。
#{}和${}的区别
{}时,就是把${}直接替换成变量的值。而Mybatis在处理#{}时,会对sql语句进行预处理,将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
使用#{}可以有效的防止SQL注入,提高系统安全性。
SpringBoot面试题
谈谈你对SpringBoot的理解
SpringBoot主要用来简化使用Spring的难度和繁重的XML配置,他是Spring组件的一站式解决方案,采用了习惯于优于配置的方法。通过.properties或者.yml文件代替了Spring繁杂的XML配置文件,同时支持@ImportResourse注解加载XML配置。SpringBoot还提供了嵌入式HTTP服务器、命令行接口工具、多种插件等等,是的应用程序的测试和开发简单起来。
为什么要用SpringBoot?
SpringBoot优点非常多,例如:独立运行、简化配置、自动配置和无需部署war文件等等。
SpringBoot的核心配置文件有哪几个?它们的区别是什么?
SpringBoot的核心配置文件是application和bootstrap配置文件。
application配置文件主要用于SpringBoot项目的自动化配置文件。
bootstrap配置文件有三个应用场景:
- 使用Spring Cloud Config配置中心时,需要在bootstarp配置文件中添加链接到配置中的配置属性,来加载配置中心的配置信息;
- 一些固定的不能被覆盖的属性;
- 一些加密或解密的场景;
运行SpringBoot有几种方式
- 用命令打包或者放容器中运行
- 用Maven插件运行
- 直接执行main方法运行
SpringBoot有哪几种读取配置的方式
- 使用@Value加载单个属性值
- 使用@ConfigurationProperties注解可以加载一组属性的值,针对于要加载属性过多的形况,比@Value,注解要更加简洁
Java设计模式
创建型模式:单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式;
结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式;
行为型模式:模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。
Dubbo面试题
Dubbo是什么
Dubbo是阿里巴巴开源的基于Java的高性能RPC分布服务框架,现已成为Apache基金会孵化项目。
为什么要使用Dubbo
使用Dubbo可以将核心业务逻辑抽取出来,作为独立的服务,逐渐形成稳定的服务中心,可用于提高业务复用灵活扩展,使前端应用能快速地响应多变的市场需求
Dubbo和SpringCloud有什么区别
两个没关联,如果硬要说区别,有以下几点
- 通信方式不同
Dubbo使用的是RPC通信,而SpringCloud使用的是HTTP RESTFul方式。 - 组成部分不同
Dubbo需要web容器吗
不需要,如果硬要用web容器,只会增加复杂性,也浪费资源
画一画服务注册与发现的流程图
流程图Dubbo默认使用什么注册中心
推荐使用Zookeeper作为注册中心,还有Redis、Multicats、Simple注册中心,但不推荐
缓存面试题
用缓存,主要是俩用途:高性能、高并发
如果不用缓存,会是什么效果?
每次查询数据都要从数据库查,严重消耗数据库性能。
为了保证高性能,用了缓存之后
缓存-高性能查询举例
缓存是如何实现高并发的
缓存-如何实现高并发.png
集合面试题
常见的集合类有哪些
conllection接口的子接口包括:Set接口和List接口
Map接口的实现类主要有:HashMap、TreeMap和HashTable等
Set接口的实现类主要有:HashSet、TreeSet和LinkedHashSet等
List接口的实现类主要有:ArrayList、LinkedList和Vector等
集合框架底层数据结构
List
ArrayList:Object数组
Vector:Object数组
LinkedList:双向循环链表
Set
HashSet(无序、唯一):基于HashMap实现的,底层采用HashMap来保存元素
LinkedHashSet:LinkedHashSet继承于HashSet,并且其内部是通过LaskedHashMap来实现的。有点类似于LinkedHashMap其内部是基于HashMap实现一样,不过还是有一点区别的
TreeSet(有序、唯一):红黑树(自平衡的排序二叉树)
Map
HashMap:JDk1.8之前HashMap有数组加链表组成,数组是HashMap的主体,链表则是解决哈希冲突而存在的;JDK1.8以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时。将链表转化为红黑树,以减少搜索时间
LinkedHashMap:继承自HashMap
HashTable:数组加链表组成
TreeMap:红黑树(自平衡的排序二叉树)
那些集合类的线程时安全的
Vector:效率低,不建议使用
statck:堆栈类,先进后出
如何边遍历边移除Conllection中的元素
边遍历边修改Conllection的唯一办法是使用Iterator.remove()
方法,如下:
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
*// do something*
it.remove();
}
一种最常见的错误代码如下:
for(Integer i : list){
list.remove(i)
}
运行以上错误代码会报ConcurrentModificationException异常,因为当使用foreach(for(Integer i : list))语句时,会自动生成一个iterator来遍历该list,但同时该list正在被Iterator.remove()修改,Java一般不允许一个线程在遍历Conllection时另一个线程修改它
ArrayList优缺点
优点
- ArrayList底层以数组实现,是一种随机访问模式,因此查找的时候非常快
- ArrayList在顺序添加一个元素的时候非常方便
缺点
- 删除元素的时候,需要做一次元素复制操作,如果要复制的元素有很多,那么就会比较耗费性能
- 插入元素的时候,同上
ArrayList和Vector的区别
相同
两个类都实现了List接口,都是有序集合
不同
- 线程安全:Vector线程安全,而ArrayList线程是非安全的
- 性能:ArrayList在性能方面要优于Vector
- 扩容:ArrayList和Vector都会根据实际需要动态地调整容量,Vector扩容每次会增加1倍,ArrayList只会增加50%
生成随机数的三种方法
第一种:new Random()
第一种需要借助java.util.Random类来产生一个随机数发生器,也是最常用的一种,构造函数有两个,Random()和Random(long seed)。第一个就是以当前时间为默认种子,第二个是以指定的种子值进行。产生之后,借助不同的语句产生不同类型的数。
种子就是产生随机数的第一次使用值,机制是通过一个函数,将这个种子的值转化为随机数空间中的某一个点上,并且产生的随机数均匀的散布在空间中。以后产生的随机数都与前一个随机数有关。以代码为例。
public static void main(String[] args) {
Random r = new Random(1);
for (int i=0 ; i<5 ; i++) {
int ran1 = r.nextInt(100);
System.out.println(ran1);
}
}
在我的编译器下产生的五个数均为85,88,47,13,54,如果采用Random r = new Random(),产生的随机数就不同,这就是确定种子导致的结果。
第二种:Math.random()
而第二种方法返回的数值是[0.0,1.0)的double型数值,由于double类数的精度很高,可以在一定程度下看做随机数,借助(int)来进行类型转换就可以得到整数随机数了,代码如下。
public static void main(String[] args) {
int max=100,min=1;
int ran2 = (int) (Math.random()*(max-min)+min);
System.out.println(ran2);
}
第三种:currentTimeMillis()
至于第三种方法虽然不常用,但是也是一种思路。方法返回从1970年1月1日0时0分0秒(这与UNIX系统有关)到现在的一个long型的毫秒数,取模之后即可得到所需范围内的随机数。
public static void main(String[] args){
int max=100,min=1;
long randomNum = System.currentTimeMillis();
int ran3 = (int) (randomNum%(max-min)+min);
System.out.println(ran3);
}
Redis面试题
Redis支持的数据类型
- String字符串
- Hash(哈希)
- List(列表)
- Set(集合)
- zset(sorted set:有序集合)
缓存概述
缓存的作用是减少服务器对数据库的访问频率,从而提高数据库的稳定性。
访问流程如下:
Redis缓存1
Redis缓存2
Redis缓存3
代码逻辑
public Goods searchArticleById(Long goodsId){
Object object = redisTemplate.opsForValue().get(String.valueOf(goodsId));
if(object != null){// 缓存查询到了结果
return (Goods)object;
}
// 开始查询数据库
Goods goods = goodsMapper.selectByPrimaryKey(goodsId);
if(goods!=null){
// 将结果保存到缓存中
redisTemplate.opsForValue().set(String.valueOf(goodsId),goods,60,TimeUnit.MINUTES);;
}
return goods;
}
多线程常见面试题
并发和并行有什么区别
- 并行:之两个或多个事件在同一时刻发生,即同时做不同的事。例如垃圾回收时,多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
- 并发:指两个或多个时间在同一时间间隔内发生,即交替做不同事的能力,多线程是一种并发的能力。例如垃圾回收时,用户线程与垃圾线程同时执行(但不一定是并行,可能会交替执行),用户程序在继续执行,而垃圾收集程序运行于另一个CPU上
创建线程有哪几种方式
- 继承Thread类(真正意义上的线程类),时Runnable接口的实现。
- 实现Runnable接口,并重写里面的run()方法。
- 使用Executor框架创建线程池。Executor框架是juc里提供的线程池的实现。
线程的run()和srart()有什么区别
- start()方法用于启动线程,run()方法用于执行线程的运行时的代码
- run()方法可以重复调用,而start()只能调用一次。
- 第二次调用start()必然会抛出运行时异常
Spring面试题
@Mapper和@Repository注解的区别
- 使用@mapper后,不需要在spring配置中设置扫描地址,通过mapper.xml里面的namespace属性对应相关的mapper类,spring将动态的生成Bean后注入到ServiceImpl中。
- @repository则需要在Spring中配置扫描包地址,然后生成dao层的bean,之后被注入到ServiceImpl中
网友评论