以下为楼主根据7年面试经验,整理的最新面试题 ,并无抄袭,偏向日常应用与开发,仅代表个人观点。
本篇文章不适用于为bat奋战和一线城市偏向算法和数据结构的大佬,仅支持二三线城市,以接口编写和功能实现为主的默默在平凡岗位上奋斗的大多数码农们,当然,包括我自己。以下附带答案均为个人理解与简单总结,若想详细了解,请自行百度。
首先介绍以下大沈阳java的薪资水平,根据加班情况或者出差情况上下略有浮动
实习生:3k - 4k 初级开发:4k - 6k 中级开发:6k - 8k 高级开发:9k - 12k 架构师:12k - 15k 真大佬(大厂经验,高并发经验,大厂管理经验):20k左右随便要
java基础
- 介绍一下break,return,continue(>4)
return:直接返回 break:循环中使用,跳出循环,以后的循环都不执行了。 continue:循环中使用,跳出循环,结束本次循环,以后的循环继续执行。
- 介绍一下static,final关键字(>4)
final主要的作用就是防止修饰的对象改变。 1.修饰变量:不允许变量改变。 2.修饰方法:防止继承的重写改变该方法。 3.修饰类:不允许继承该类。防止被重写。 static:可以在没有建立对象时候使用。 1.修饰变量:是全局变量,在类加载之后放于方法区,只在初始化时加载一次,且全局共享。如果不赋初值就默认为0. 2.修改方法:静态方法不能调用非静态的变量和方法(因为非静态的方法和变量需要对象来调用,但是不可能使用) ,非静态方法能够使用静态方法,使用“类名.方法”调用,而不能用对象调用。因为this也是通过对象调用,所有不 能使用this。可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的 主要用途。 2.1为什么要使用静态方法 静态方法的好处就是不用生成类的实例就可以直接调用。 static方法修饰的成员不再属于某个对象,而是属于它所在的类。只需要通过其类名就可以访问,不需要再消耗资源 反复创建对象。 在类第一次加载的时候,static就已经在内存中了,直到程序结束后,该内存才会释放。 如果不是static修饰的成员函数,在使用完之后就会立即被JVM回收。 什么时候使用static? 如果这个方法是作为一个工具来使用的,就声明为static,不需要new一个对象就可以使用。比如:connect DB就可 以声明一个Connection()的static方法, 3.修饰类:只有一种情况,静态内部类。 特点:1.内部类只能访问外部类静态的变量和方法。 2.静态内部类能声名普通的变量和方法,而普通内部类不能声名静态方法和变量。 使用场景:静态内部类使用场景一般是当外部类需要使用内部类,而内部类无需外部类资源,并且内部类可以单 独创建的时候。 4.修饰代码块:可以优化性能,在类加载时调用。且只调用一次。(加载顺序 父类的静态代码块-子类的静态代码块 -父类的构造方法-子类的构造方法),静态语句块中只能访问定义在静态语句块之前的变量,定义在它之后的变量可 以赋值,但不能访问
- 介绍一下内部类(>4)
内部类包括:成员内部类,局部内部类,静态内部类,匿名内部类 使用内部类的原因: 1.可以实现多重继承。(不同的内部类可以继承不同的类)。 2.内部类可以更好的隐藏。 3.当我们不想写接口的实现或只是用一次对象时可以使用匿名内部类。(+) 4.每个内部类都是一个单独的个体。
- 介绍一下什么时候使用== 什么时候使用equals(>4)
==:比较的是地址也就是栈。ps 或是一些常量放在方法区。 equals:比较的是值,也就是堆。一般都是封装类型。
- 说说int和integer(>4)
int:基本类型,放于方法区,使用==可以比较。 integer:封装类型。使用equals比较,在对象传值时(非计算情况),一般建议使用integer,因为integer有 0与null可以表示不同含义
- 说说常用的工具类(>5)
commons包,fastjson包等
- 描述一下集合类 list map hash的区别(>5)
collection collect为存储数据的集合类的顶级接口。所以不能实例化,只能实现collection, 长度可变,集合为引用类型 list和set是collection的实现类 list list有序,可以重复,可以为空,实现类有ArrayList、LinkedList 和 Vector。 linklist以链表的方式存储增删更快,线程不安全,效率高。 arraylist以数组的方式存储,查询更快 ,效率高,线程不安全。 vector线程安全,效率低,增长率为100%,数据量较大的数据 set 不可以重复,无序,treeset,hashset,linkhashset为set的实现类。 hashset 数据结构是哈希表,按照hash值排序,不存在重复值,通过hashcode和equals判断。线程安全,存取 快。元素的哈希值是通过元素的hashcode方法 来获取的, HashSet首先判断两个元素的哈希值,如果哈希值一 样,接着会比较equals方法 如果 equls结果为true ,HashSet就视为同一个元素。如果equals 为false就不 是同一个元素。哈希值相同equals为false的元素是怎么存储呢,就是在同样的哈希值下顺延(可以认为哈希值相 同的元素放在一个哈希桶中)。也就是哈希一样的存一列。 treeset 可以自然排序。不可重复。 LinkedHashSet 会保存插入的顺序 map map是map的接口的实现类,为键值对的,包括hashmap,treemap,hashtable,linkedtreetable hashmap 且键唯一,键 值 可为空,线程不同步。 treeMap 可以对集合中的键进行排序 LinkedHashMap 保存了记录的插入顺序 hashtable key和value的值均不允许为null;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也 导致了Hashtale在写入时会比较慢。 线程安全问题 linklist arraylist hashset linkhashset线程不安全 vector hashtable为线程安全 stringbuild为线程不安全 stringbuffer为线程安全 ArrayXxx:底层数据结构是数组,查询快,增删慢 LinkedXxx:底层数据结构是链表,查询慢,增删快 HashXxx:底层数据结构是哈希表。依赖两个方法:hashCode()和equals() TreeXxx:底层数据结构是二叉树。两种方式排序:自然排序和比较器排序
在小公司,回答上这些已经非常好了,
- integer使用什么比较数值(>7)
使用equals比较,但是-128-127之间 也可以使用==比较,因为直接使用了int (这个是重点考察哒)
- 介绍一下bigdecimal(>7)
在金额数值计算时使用,避免精度丢失
- 说说java内存模型(>8)
JVM就是java虚拟机,每一个JVM都包括堆,栈,本地方法栈、方法区,指令计数器及其他隐含寄存器。 堆:负责存储对象实例。 栈:存储基本类型和对象的引用。 方法区:存放着类的静态变量,常亮,类的信息等。 本地方法栈:与栈相类似,只不过存放的是方法。
这个网上比较多,篇幅有限,请自行百度吧。
- 说说gc(>8)
如果内存空间满了改怎么办,JVM提供了GC-也就是垃圾回收机制。当内存溢出自动进行垃圾处理。一般都是堆发生垃 圾回收。而堆被分为了三部分分别是新生代 ,年老代,持久带,新生代又被分为Eden、Survivor1、Survivor2这 三块,当一个对象被新建后会被放入eden中较大的直接放入年老代中),当eden被存满后会发生minor GC,此时 eden会将内存中不用的空间清除并把剩余的数据放入Survivor1,当下一次eden被存满后,重复上次操作,eden 和Survivor1中数据会一起存放进Survivor2中,直到Survivor1或Survivor2存放满,这时会把存放满 的Survivor1或Survivor2数据存进年老代中,而当年老代被存满后会发生full gc此时会清理年老代的内存。
这个网上比较多,篇幅有限,请自行百度吧。
- 说说java的反射,private的类或方法是否能反射到(>8)
private类型能够反射到
- 通过了解内存模式和gc 说说自己的理解(>9)
集合类使用时要谨慎,防止内存泄漏,因为gc使系统短暂停止。 减少new次数,因为对多次占用堆内存 等 篇幅有限,请自行百度吧
- 两个integer类型 值都是127 a=b 返回值,两个integer类型 值都是128 a=b 返回值 (>10)
127返回true 128返回false
java基础肯定是必不可少的问题,对于初中级开发,问的比较多,这是会伴随你职业生涯的技能,而且没有太难的知识点,需要大量准备。
数据库
- 简单的sql编写 如两表关联(>4k)
不多说
- 左连接与右连接(>5k)
左连接 left join on 以左表数据为主 右连接 right join on 以右表数据为主
- 为什么索引能提高查询速度(>7k)
因为不适用索引全表搜索,这样会产生多次读取磁盘的行为,是物理行为,所以比较慢。(io) 使用索引3次io即可实现查询,所以会提高速度。
此处只提供简单概括,具体自行百度
- 什么情况会不走索引(>7k)
1.查询列为varchar类型 但是where后没有添加‘’(隐式转换) 2.<>、IN,NOT IN、exists,not exists等关键字 3.使用like时通配符在前(like在后索引不失效) 4.or会使索引失效(可以在每个or中都加入索引) 5.索引列进行函数计算 6.对索引进行运算会使索引失效
- 是否了解rbac权限模型 介绍一下表(>7)
用户,角色,菜单,用户角色,角色菜单表
- 描述一下怎么实现分页(>7)
limit语法
- sql优化经验或者sql编写技巧(>9k)
可以参考适当的背一些,但是都不如掌握explain语法。建议掌握。
- 描述mysql的两种搜索引擎(>9k)
- 聚集索引与非聚集索引区别(>10)
如果想了解“聚集索引和非聚集索引”那么可以先看看B树和B+树 下面说说他们的区别 聚集索引:1.属于Innodb。 2.按照主键B+树的排列方式存放,子节点存放的就是数据。(如果没有主键,以第一列为聚集索引) 3.只有一个聚集索引。 4.普通索引指向聚集索引 非聚集索引:1.属于MyIsam。 2.普通索引和非聚集索引没什么区别。 3.存放的是地址。
- 说一下mysql的事务隔离级别(>10)
未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据。 提交读(Read Committed):只能读取到已经提交的数据。 可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL 标准中,该隔离级别消除了不可重复读,但是还存在幻读。 串行化(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞,效率最低,可以避 免脏读,幻读,不可重复读。 这四种隔离等级从上向下依次变低
- b tree与b+tree (>12k)
篇幅有限请自行百度
同样,必备技能,但是小公司没有问的那么深,能熟练的书写sql语句,掌握常用语法就已经达标。在sql优化方面explain可以说是必杀技了,建议了解。
设计模式
- 说说了解哪些设计模式 (在我这,一般到这就结束了。。)(>5)
根据了解扩展
- 详细描述一下工厂模式,代理模式。(>7)
概念:委托一个代理类对另一个类进行控制(代理类中有被代理类的对象,同时可以在代理类中增强) 使用场景:aop(可以控制被代理类是否被调用,是否被代理)。 优点: 1.确保被代理类的隐秘性 2.降低耦合性(不用挨个加需要增强的方法) 分静态代理,jdk代理,CGLib动态代理
篇幅有限 具体的请自行了解
- 说说在日常编码中使用过哪些设计模式(>7)
代理模式,工厂模式,外观模式,策略模式。 请自行扩展。
- 介绍一下外观模式(>8)
它为子系统中的一组接口提供一个统一的高层接口。这一接口使得子系统更加容易使用。(体现为service和dao, 一个service可以调用多个dao)
- 代理模式,装饰者模式,适配器模式三者类图相同 说说三者区别 (>9)
适配器模式:主要强调适配,在不使用继承的情况下,可以调用其他不同的接口。 代理模式:主要强调控制,被代理的类不一定执行,可能不允许被代理。 装饰者模式:主要强调增强,目的是在原类中加入需要装饰。而被装饰者一般情况下都会被执行
- 介绍策略模式和状态模式的区别(>10)
这个也比较常问,所以好好理解 建议仔细研究一下:https://www.zhihu.com/question/23693088
设计模式在日常使用中使用的不多,但是也需要了解一些基础来扩宽以后的视野。现在阶段可以适当了解应付一下面试。
mybatis
- #{}与%{}区别(>5)
{}是预编译处理,${}是字符串替换。 Mybatis 在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement 的 set 方法来赋值; Mybatis 在处理${}时,就是把${}替换成变量的值。 使用#{}可以有效的防止 SQL 注入,提高系统安全性
- 说说sql注入(>5)
账号密码输入‘’ or 1=1 查询语句变成以下形式 SELECT * FROM Users WHERE username=‘’ or 1=1 AND password=‘’ or 1=1;
- 说说常用标签(>5)
foreach,where,if,sql,set,include,sql,choose,curd不多说
- mysql自增主键怎么返回(>6)
标签加入keyProperty="id" useGeneratedKeys="true"
- 说说mybatis的一级缓存和二级缓存 (>7)
一级缓存是自动开启的。是sqlSession级别的缓存。个人理解就是同一个事务之内,调取两次相同sql. 二级缓存是mapper级别的,只要是对一个mapper调用就可以使用二级缓存。
- mybatis的实现原理(>9)
一言难尽,请自行百度。
必备技能,但是以上基础部分需要重点掌握。根据自己的薪资可以自行提升难度。
分布式
- 介绍一下分布式,说说对分布式的理解(>5)
分布式侧重将一个系统拆分成多个业务单元,例如一个门户网站里面可能有登录、视频、图片等,每一个都可以拆分出 来独立部署,而且每一个都可以弄成集群,视频服务集群,图片服务集群,主系统可以对这些子系统进行调用,子系统 之间可以有调用关系也可以没有,看实际业务情况。 网上很多,请自己总结
- 分布式事务(>10)
tcc,seata等,篇幅原因请自行查看
- 分布式锁(>10)
Redission等,篇幅原因请自行查看
分布式事务分布式锁等小公司使用并不多,初级,中级了解即可,如果想拿到一个更高的薪资(装b)建议掌握。
spring全家桶(吃饭的家伙)
spring
- 介绍一下spring的理解(>5)
提供了ioc,aop,用于解耦。
- spring的依赖注入和控制反转是什么意思(>5)
依赖注入与控制反转是一回事 依赖注入:被注入对象依赖IoC容器配置依赖对象。 控制反转:bean的控制交于工厂。
- 和new()相比,spring有什么优点(>6)
1.bean交于容器统一管理 2.节省堆内存
- ioc与aop的实现原理(>7)
ioc工厂模式 aop代理模式 涉及源码,篇幅有限 请自行百度
- 说一下自己了解spring注入失败的原因(>6)
1.bean重名 2.bean起名为set或get(其他关键字可能也会有问题) 3.循环依赖
- 能介绍一下spring的循环依赖吗 (>10)
循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A
- 说一下spring的事务传播级别(>10)
PROPAGATION_REQUIRED–支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 PROPAGATION_SUPPORTS–支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY–支持当前事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW–新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED–以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER–以非事务方式执行,如果当前存在事务,则抛出异常。
- bean的初始化流程 (>10)
涉及源码,篇幅有限 请自行百度。
spring cloud
- 是否使用过微服务,说说对微服务的理解 (>5)
1.按照业务拆分服务,方便于管理开发。 2.更加方便集群化建设。 3.更加容易容器化建设。
- 在项目中使用过哪些微服务组件(>6)(根据不同微服务生态)
Netflix和爸爸版生态 需要了解一个
- 说说微服务生态的各组件的选型(>7)
建议选型爸爸版 注册与配置:nacos 服务间调用:dubbo/openfeign 网关:getway 监控:sentinel 优点 1.还在持续开源,未来或许还有其他功能 2.nacos比eureka更加强大,有命名空间,组等功能呢。 3.性能更加优越。 4.中文文档齐全。
- 说说对网关的理解(>7)
在没有API网关作为统一出口的情况下,需要调用方自己组合各种服务,而且容易让调用方感知后端各种服务的存在, 加入网关后,客户端调用服务需要通过网关来进行,并且网关可以处理路由,安全,限流,缓存,日志,监控,重试, 熔断等事务,使业务开发更纯净。
- 说说对熔断的理解(>7)
由于网络原因或者自身的原因,服务并不能保证 100% 可用,如果单个服务出现问题,调用这个服务就会出现线程阻 塞,此时若有大量的请求涌入,Servlet 容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故 障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的 “雪崩” 效应。为了解决这个问题,业界提 出了 熔断器模型。
- 在微服务体系中 服务的注册和暴露的过程 (>8)
服务向注册中心发送请求,注册中心获取到服务信息后,保存在本地,当需要服务间需要调用时,服务会拉取注册中心 的服务列表,获取被调用服务信息,执行调用。 并且有着心跳的概念,及在固定时间内服务向注册中心发送请求,表明自己还活着。
- 服务间调用如果响应时间过慢造成无响应怎么办(>9)
可以加大调用允许保持连接的时间,但是如果是响应过慢,对用户体验特别差,所以不建议。所以需要以下 1.排查被调用服务器是否有优化余地,如sql等。 2.如果是少部分请求,加入熔断,提升用户体验, 3.如果允许可以使用异步或者mq。以异步的方式获取数据。
spring mvc(如果简历写过)
- spring mvc的原理 (>7)
(1)客户端(浏览器)发送请求,直接请求到DispatcherServlet。 (2)DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler。 (3)解析到对应的Handler后,开始由HandlerAdapter适配器处理。 (4)HandlerAdapter会根据Handler来调用真正的处理器开处理请求,并处理相应的业务逻辑。 (5)处理器处理完业务后,会返回一个ModelAndView对象,Model是返回的数据对象,View是个逻辑上的View。 (6)ViewResolver会根据逻辑View查找实际的View。 (7)DispaterServlet把返回的Model传给View。 (8)通过View返回给请求者(浏览器) 详细答案请自行百度
- 介绍一下dispatchservlet (>8)
1. 请求会首先发送到DispatchServlet,这是spring的前置Servlet,它会接收请求并转发给spring的MVC controller,也就是业务controller 2. DispatchServlet通过HandlerMapping(处理器映射)确定将请求转发给哪个controller,HandlerMapping主 要通过请求中的URL确定映射关系的 3. DispatchServlet将请求转发给确定的controller之后,DispatchServlet卸下请求的负载,controller负责处 理这个请求,一般会通过调用service层进行业务逻辑处理 4. 当controller处理完请求后,它会把业务处理结果封装成model,为了使处理结果的model在页面上更好的展示, controller还会指定展示model对应的view(比如一个JSP页面),当controller确定了model和view之后,会把它们 以请求的形式再转发给DispatchServlet 5. DispatchServlet通过查询ViewResolver(视图解析器)找到view对应的页面 6. DispatchServlet最终把model交给页面进行渲染 7. 页面对model进行渲染,将结果展示到客户端,整个请求结束
- 说说对上下文的理解(>8)
context就是“容器”,放的就是应用程序的所有资源,要用时候就访问它,所以context里面的东西,在同一个应用程 序里面是全局的;web上下文可以看成web应用的运行环境,一般用context名字来修饰,里面保存了web应用相关的一 些设置和全局变量
- 说说与spring boot的区别(>10)
spring mvc需要大量xml配置,spring boot遵守着约定大于配置,springboot具体实现可以参考下文
spring boot
- 介绍一下编写接口的注解(>5)
@RestController,@RequestMapping,@RequestParam,@Service,@RequestBody,@requestmapping等
- 介绍一下spring boot事务(>5)
一个接口内,数据全部处理完成或者处理失败,防止一部分失败一部分成功。 使用@Transactional(rollbackFor = Exception.class)
- 描述一下restful风格(>7)
一种软件架构风格、设计风格,增删改查接口全部使用一个命名,使用请求类型来(get,post,put,delete)确定调 用的那个接口。
- springboot的启动原理(>8)
1.运行 SpringApplication.run()方法 2.SpringApplicationRunListeners listeners = this.getRunListeners(args);获取监听器 3.listeners.starting()触发applicationStartedEvent 启动监听器 4.准备好环境environment 触发applicationEnvironmentPrepareEvent 5.创建一个spring上下文createApplicationContext() 6.初始化上下文 1):获取要启动类包的地址 2):转为BeanDefinitionRegistry 3):通过注解扫描出bean 4):调用BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);将启动类BeanDefinition注册到IoC容器的beanDefinitionMap中 7.刷新上下文refreshContext(注入各种需要的bean 以下是bean的生命周期 !!关键) //设置BeanFactory的后置处理. 空方法,留给子类拓展用。 (1)postProcessBeanFactory(beanFactory); //调用BeanFactory的后处理器, 这些后处理器是在Bean定义中向容器注册的. (2)invokeBeanFactoryPostProcessors(beanFactory); (3)实现自动化配置 //注册Bean的后处理器, 在Bean创建过程中调用. (4)registerBeanPostProcessors(beanFactory); //初始化上下文中的消息源,即不同语言的消息体进行国际化处理 (5)initMessageSource(); //初始化ApplicationEventMulticaster bean,应用事件广播器 (6)initApplicationEventMulticaster(); //初始化其它特殊的Bean, 空方法,留给子类拓展用。 (7)onRefresh(); //检查并向容器注册监听器Bean (8)registerListeners(); //实例化所有剩余的(non-lazy-init) 单例Bean. (9)finishBeanFactoryInitialization(beanFactory); //发布容器事件, 结束refresh过程. (10)finishRefresh(); 7.ApplicationRunner和CommandLineRunner启动
- spring boot是怎么实现约定大于配置的(>8)
涉及源码,请自行百度。
- 描述一下spring boot中的异步(>8)
@EnableAsync使异步调用@Async注解生效 调用后立即返回固定对象,释放线程,程序在后台执行。前台无感知。
- 描述一下跨域是如何处理(>8)
添加cors配置。指定后台地址允许访问。
- 介绍一下自定义注解(>9)
1.基于aop 2.拦截器 3.ConstraintValidator注解实现验证
- 介绍一下@resource和@Autowired区别(>9)
@Autowired注解由Spring提供,只按照byType注入;@resource注解由J2EE提供,默认按照byName自动注入2、 @Autowired默认按类型进行装配,@Resource默认按照名称进行装配。”
对于小公司,技能要求真心不多,数据结构算法,完全用不上,那么最重要的还是springboot的使用,如果你能熟练的书写接口,熟练掌握ssh,那么找个一个理想的工作是不难的。所以,springboot接口编写一定要6。
spring security
- 描述一下spring security作用,并分别介绍以下(>7)
验证与鉴权。 验证:验证密码是否正确 鉴权:判断用户是否有权限访问接口。
- spring security token的存储方式 (>7)
内存,数据库,redis,jwt
- jwt和redis存储有什么区别 (>8)
jwt只能验证,并不能对token删除修改等,如果需要踢人,或者需要对token进行操作,请选择redis.
- 描述一下spring security核心配置类 (>8)
- 简单介绍一下spring security的原理(>9)
是一大堆过滤器链,分别验证
- 怎么实现验证码功能(>9)
- 记住我功能怎么实现(>9)
在小公司spring security+oauth2人才真的少,所以学吧老铁。如果未来想成为公司的架构的参与者,或者不满于curd,spring security应该是值得你掌握的。
中间件
elasticsearch
- 简单介绍一下es (如果简历有写)
Elasticsearch是一个开源的分布式、RESTful 风格的搜索和数据分析引擎,它的底层是开源库Apache Lucene。并 有以下特点 1.分布式实时文件存储,并将每一个字段都编入索引,使其可以被搜索。 2.实时分析的分布式搜索引擎。 3.可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。
- 说说es的倒排索引是怎么回事 (>6)
记录每个词条出现在那些文档,以及文档中的位置,可以根据词条快速定位到包含这个词条的文档及出现的位置
- es查询索引的语句怎么写 (>6) (以上两个问题答不上来说明不会 不用往下问了 二三线使用概率还是很小的)
GET /20211201-logs/_search { "query": { "match_all": {} }
- es使用的场景是什么(>7)
全文检索,精准查询,elk等
- spring boot整合中用了什么客户端 (>7)
简单的可以使用spring提供的ElasticsearchTemplate 复杂的可以使用RestClient
- 查询前缀名相同的索引的查询语句 (>8)
GET /*_logs/_search { "query": { "match_all": {} }
使用的非常少,有写的咱就得问啊。不是必须掌握。
rabbitmq
- mq的作用是什么(>5)
削峰,异步,解耦
- rabbitmq使用场景(>6)
向其他服务器异步发送消息 大量请求怼过来,按照服务器性能慢慢拉取适量请求
- 说说交换机种类(>7)
fanout:发送给所有绑定该交换机的队列。 Direct:默认的交换方法,按照提供的key去寻找队列。如果key为A,数据只能发送到A的队列中。 Topic:模糊匹配,只要符合该格式就可以。可以存在两种特殊字符“*”与“#”,用于做模糊匹配,其中“*”用于匹配 一个单词,“#”用于匹配多个单词(可以是零个)。如*.C.# 可以匹配A.C.B.不能匹配A.B.C.(其中以banding key 关联) head:根据消息内容中的headers属性进行匹配。
- 怎么保证消息不丢失(>8)
1:队列持久化硬盘 2:手动ack 3:确认是否发送成功 4:集群化处理 5:异地容灾 6:发送消息持久化到db中 进行消息的重新发送 7:消费者消息固话到db中 通过消息id判断是否重复消费
- 说说ack和nack
手动应答是否接收成功,否则会出现消费者一直占用这队列的情况
- 了解延时队列和死信队列吗 (>10)
死信队列:如果有有错误消息 如果手动nack同时将消息放回到队列中 那么这条消息会反复消费 留在队列中 如果nack后将消息丢弃 那么如果碰到网络抖动 消息也会丢失 。 所以 建立死信队列避免消息丢失。 延时队列:在一定条件后触发执行
mq在小公司应用的也比较少,但是强烈建议了解一下,如果不写一般也不会问,但是如果使用一定要在一定程度保证消息的准确性,如:防止长期占用一个队列,消息不消费的情况。
redis
- redis的使用场景(>5)
使用自动过期策略存放token 热点数据存放redis 利用原子性自增计数器 分布式锁
- redis为什么比数据库快(>6)
一.纯内存操作 二.单线程反而避免了多线程的频繁上下文切换问题
- redis5个基本数据类型(>6)
string,list,map,set,zset
- redis雪崩 击穿 穿透(>8)
- 雪崩 击穿 穿透的解决办法 (>9)
一 缓存雪崩:大量key同时失效,大量请求发送到db上,导致db宕机。 解决办法:设置key过期时间时,使用随机数 二 缓存穿透:大量请求请求一个缓存中没有的key,这些请求直接怼到db上,造成宕机。如发送为负数的入参时。(一般为黑客侵入) 解决办法:1.加入入参的验证,防止非法入参。 2.nginx加入拦截,防止同一个ip大量的请求。 3.使用布隆过滤器判断数据库是否存在,不存在直接返回。 三 缓存击穿:热点key突然失效,大量的请求怼到db,db宕机。 解决办法:1:设置热点缓存不过期 2:加入互斥锁
- redis 单线程还是多线程 为什么单线程还是这么快(>10)
一.纯内存操作 二.核心是基于非阻塞的 IO 多路复用机制 三.单线程反而避免了多线程的频繁上下文切换问题
- 描述一下redis的持久化(>10)
RDB:RDB做镜像全量持久化,将redis所有的数据以二进制保存,RDB会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据。他是隔一段时间开启子线程,持久化这段时间的数据。 AOF:增量持久化,保存当前一秒或者当条指令,以文本保存
- redis与数据库数据一致性如何解决(>12)
先删缓存,再更新数据库,然后采用双删一致
最常用中间件,建议必须掌握。小公司使用的背景大多数是利用key过期时间保存token,或者利用redis原子性,计数使用,可能有少量从缓解数据库压力考虑。所以后几道题目应用的很少,但是,这种常用中间价在面试前应该背一下的。
mycat(简历有再问)
- 什么环境使用mycat(>5)
- 分库分表的背景(>5)
- 当前环境是否适合分库分表
- mycat原理(>7)
- 分库分表后怎么关联查询,分页,排序(>8)
很少使用,楼主也没有过应用经验,但是简历有写还是会问的。这里就不献丑提供经验了。没必要死记硬背。
代码规范
- idea格式化代码的快捷键是什么(>5)
ctrl+alt+l
- 是否对自己编写的接口建立接口规范(>7)
建议了解阿里规范
- 是否对自己建立的表建立规范(>7)
建议了解阿里规范
- 是否对自己编写的代码树立规范(>7)(>7)
建议了解阿里规范
- 类和注释经常写吗,是怎么实现的(>7)
建议了解阿里规范
- 对于规范是否有插件或者自己的体系检查
建议了解阿里 p3c
- 使用什么接口文档,其中需要注意什么。
对于我来说,一个良好的编写习惯是优秀程序猿必不可少的品质,无论在日常的编写还是以后作为teamleader或是管理者,是一定需要的。否则怎么跟小弟装b,这里我会重点问一下,可惜,达到要求的很少。我感觉如果在面试过程中突出表现自己有这方面经验,会脱颖而出。
多线程
- 如何理解多线程(>5)
如果不使用多线程 只有一件事干完才能干另一件事 那么你在听歌时候只有听歌的线程在执行 就不能评论,而是用多 线程后可以在听歌时候同时评论 同时提高对内存的使用率 避免内存空闲(但是不能创建太多线程,速度会变慢)
- 描述一下线程状态 (>8)
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。 就绪状态: 当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度 器的调度。 运行状态: 如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂, 它可以变为阻塞状态、就绪状态和死亡状态。 阻塞状态: 如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞 状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种: 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超 时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。(注意,sleep是不会释放持有的 锁) 死亡状态: 一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
- 介绍一下线程池(>8)
Java中开辟出了一种管理线程的概念,这个概念叫做线程池,有以下优点 (1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。 (2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。 (3)提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用 线程池可以进行统一的分配,调优和监控。
- 什么是线程安全 ,介绍几个java中线程不安全的类或方法 (>8)
多次执行线程,结果不变,那么线程安全 StringBuilder,simpledateformat等
- Executors的四个线程池为什么不建议使用 (>9)
造成oom,详细解释清自行百度。
- 介绍一下 volatile、ThreadLocal (>10)
volatile:保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说 是立即可见的。(实现可见性)只能保证对单次读/写的原子性。i++ 这种操作不能保证原子性。 ThreadLocal:一个线程的局部变量(其实就是一个Map),ThreadLocal会为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,将对象的可见范围限制在同一个线程内,而不会影响其它线程所对应的副本。 这样做其实就是以空间换时间的方式(与synchronized相反),以耗费内存为代价,单大大减少了线程同步(如synchronized)所带来性能消耗以及减少了线程并发控制的复杂度。
- 介绍一下锁(>12)
很多类型,篇幅原因,请自行百度。
多线程总体问的比较少,小公司使用场景不多。了解即可。或者会问但是用的真心少。
算法
冒泡排序打天下!你懂的!
总结
- spring基础概念和简单原理需要掌握。
- spring boot接口一定要写的6,非常非常的溜。吃饭的家伙。
- 在接口编写的过程中,经常使用的java基础要熟练掌握,如数值比较,集合类处理等。
- redis中间件必须掌握,rabbitmq建议至少了解。
- mybatis,mysql不都说,至少把上文面试题掌握,如果explain语法很熟练,这点可以干掉大多数竞争者。
- spring cloud建议掌握一种生态,建议爸爸版,这点是加分项。
- spring security和代码规范建是一个突出与他人等级差异很好技能,或许spring security比较花费时间,但是规范可以在日常中严格要求自己养成。也是加分项。
- 上其他不必须掌握,但是均为可以装x。