面试题目总结
- 前言
-
- JWT使用
- token是如何生成
- 微服务链路检测
- 泛型的实现
- cglib的实现
- 有哪些开发规范
- 看过哪些源代码
- 熔断器的使用
- 高并发场景
- mybatis一级缓存(同一个SqlSession内),二级缓存(不同的SqlSession间,mapper)
- docker (k8s)
- docker-compose
- JVM调优
- springcloud用过什么组件
- CAP理论(C——数据一致性,A——服务可用性,P——服务对网络分区故障的容错性),
- java反射原理
- zookeeper 调用流程处理方法,调用方式
- 微服务调用元素
- Java浅拷贝和深拷贝的理解和实现方式
- java悲观锁和乐观锁区别
- 后端实现跨域
- Spring Boot、Spring MVC、Spring之间的区别?(Spring Boot本质是什么?)
- Spring Boot Starter 是什么?
- 如何自定义Spring Boot Starter?(如何扩展Spring Boot)
- Spring Boot 的自动装配原理是什么?(源码分析哦)
- Spring Boot 的启动流程是什么?
- 有没有看过 Spring Boot 源码?你觉得最神奇的地方是什么?谈谈理解,有哪些特性
- 对服务注册中心的理解
- 对网关的理解
- jvm 原理
- 你是怎么设计微服务
- redis用过锁吗
- redis内存优化
- redis淘汰策略
- Redis最为常用的数据类型主要有以下
- redis 的应用场景
- spring bean 不是线程安全的
- 幂等性问题
- 微服务的架构设计
- mybatis原理
- mybatis $ # 的区别
- TCP协议详解
- java sync 锁的是什么
- hashmap的原理
- springboot的初始化原理
- jvm的分区(五大分区)
- GC垃圾回收机制
- 怎么执行GC垃圾回收
- springboot是怎么实现springmvc的东西的
- mysql怎么运用分库分表
- 用过哪些设计模式
- 对Euraka服务注册中心的理解
- 运用Euraka遇到的问题
- zuul有哪些过滤器
- 分页插件的好处是什么
- 封装类型和基本类型的区别
- 怎么解决并发的
- shrio的使用
- springmvc的源码
- in id方法有用到索引吗
- list的子类
- 并发包
- 对dubbo的理解
- 注册中心挂了会产生什么影响?
- 为什么使用Dubbo?
- 什么叫事务?简称ACID
- 线程中变量的可见性
- 引用数据类型包括:
- java排序算法
- 10G的文件导入带数据库中怎么实现(怎么快速把10G的文件解析出来)
- 微信朋友圈的点赞功能怎么实现,好友可以看到,共同好友可以看到
- js == === 的区别
- springboot 的 starter的工作原理 自动装配
- Servlet的生命周期
- 如何取得每个部门薪资前三名的人员名称?
- 查询两张表中没有交集的数据
- swagger 注解参数
- synchronized 的方式
- 接口和抽象的区别
- 怎么把抽象类变为接口
- 索引联合
- mysql的事务隔离级别
- 索引的数据结构
- redis是怎么实现单线程的
- spring bean 为什么没有状态
- Map<String, Object> map = new HashMap<String, Object>()用到了什么设计模式
- 工厂模式有几种写法
- redis什么时候会变卡
- 单例模式有几种写法(五种)
- 红黑树是怎么保证自平衡的
- 数据结构有哪些
- js的选择器
- IOC的实现原理
- DI(依赖注入)
- AOP原理
- Autowired 和Resources的区别
- sprngboot文件上传用什么参数
- 依赖注入有几种方式
- 负载均衡用了哪些算法
- get方法参数为中文会变成什么
- mysql怎么存储表情符号
- 进程和线程
- 线程的生命周期
- mysql的优化方向
- 过滤器Filter和拦截器Interceptor的区别
- String 为什么不能被继承
- 怎么实现自动登录的
- Springcloud和dubbo的区别
- sync和lock的区别
- B+tree 的的特点
- redis持久化机制
- JAVA线程池有哪些配置参数,各自的作用是什么?
- mysql锁有哪些
- 锁的级别
- mysql索引有哪些?
- mysql性能优化
- explain 关键字sql执行情况
- 基本数据类型有哪些
- Mybatis-Plus 表里面有两个主键(复合组件)应该怎么插入
- 分布式事务
- 同一个类下面:两个方法A调用B,B有事务,整个方法有没有事务?
- logback和log4j的区别
- int主键和string主键效率哪个高
- 服务治理是什么
- Mq如何防止消息丢失解决方案
- 订单延迟30分钟未支付,自动关闭
- redis使用在分布式锁的场景
- mysql 视图和表的区别
- 表和临时表的区别
- 一个文件夹里面有多个文件夹中有多个文件,如何读取里面的txt文件的名称
- SpringBoot 在项目启动之后执行自定义方法的两种方式
- 对微服务的理解
- java 异常的原理
- spring 原理
- sleep和wait有什么区别
- Java 实现动态代理主要涉及哪几个类
- 数据库大数据量分页查询方式
- nacos和eureka的区别
- mq的三大特性
- redis与mysql数据一致性问题
- 微服务之间的通讯方式,传递token
- 联合索引是原理
- Spring和Spring Boot之间存在以下主要区别
- 录用你了,你首先应该做什么
- 你的优势和劣势是什么?
前言
一名Java后端在重庆面试亲身经历,每一场面试脑海中印象比较深刻的问题记录下来,并且总结,找出答案,分享出来。
现在面试问的问题都相对来说比较深入
话不多说上题目:
JWT使用
客户端接收服务器返回的JWT,将其存储在Cookie或localStorage中。
此后,客户端将在与服务器交互中都会带JWT。如果将它存储在Cookie中,就可以自动发送,但是不会跨域,因此一般是将它放入HTTP请求的Header Authorization字段中。
Authorization: Bearer
当跨域时,也可以将JWT被放置于POST请求的数据主体中。
相对传统token jwt token不需要保存在服务器端
2. JWT实现过程
第一步,用户提交用户名和密码给服务端,如果登录成功使用jwt创建一个token,并给用户返回
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
注意:JWT生成的token是由三段字符串组成的,并且用.连接起来
第一段字符串,HEADER,内部包含算法和token类型,json转化为字符串,然后做base64url的转码
{
“alg”: “HS256”,
“typ”: “JWT”
}
第二段字符串,payload,自定义值.
json转化为字符串,然后做base64url的转码
由于只是做了一层编码,所以这些信息都是透明的。不建议在里面传密码之类的敏感信息。
{
“sub”: “1234567890”,
“name”: “John Doe”,
“iat”: 1516239022
}
第三段字符串
前两部分的密文拼接起来
对前2部分的密文进行HS256加密 + 加盐
对HS256加密后的密文再做base64url加密
以后用户再来访问,需要携带token,后端需要对token进行校验
获取token
第一步:对token进行切割
第二步:对第二段解码,获取payload,检测token是否超时
第三步:把前两段拼接再次执行HS256加密,把加密后的密文和第三段比较。如果相等,认证通过
参考博文:https://www.jianshu.com/p/cb886f995e86
token是如何生成
微服务链路检测
链路追踪
SkyWalking or Zipkin
ZipKin:服务调用的请求和响应中加入ID,标明上下游请求的关系。利用这些信息,可以可视化地分析服务调用链路和服务间的依赖关系
Spring Cloud Sleuth是对Zipkin的一个封装,对于Span、Trace等信息的生成、接入HTTP Request,以及向Zipkin Server发送采集信息等全部自动完成。
参考博文:
https://www.cnblogs.com/duanxz/p/7552857.html
https://www.cnblogs.com/duanxz/p/7552857.html
泛型的实现
泛型的实现是靠类型擦除技术, 类型擦除是在编译期完成的, 也就是在编译期, 编译器会将泛型的类型参数都擦除成它的限定类型,如果没有则擦除为object类型之后在获取的时候再强制类型转换为对应的类型。 在运行期间并没有泛型的任何信息,因此也没有优化。
cglib的实现
动态代理
有哪些开发规范
REST full
看过哪些源代码
熔断器的使用
在启动类中,需要添加 @EnableCircuitBreaker 注解
定义 Hystrix 处理类
OrderClientServiceFallbackFactory implements FallbackFactory<OrderClientService>
重写 create方法
里面再重写熔断的默认返回
配合feign在接口上面加上工厂类
@FeignClient(value = "MICROSERVICE-ORDER", fallbackFactory = OrderClientServiceFallbackFactory.class)
开启熔断
feign:
hystrix:
enabled: true
参考博文: https://blog.youkuaiyun.com/eson_15/article/details/86628622
高并发场景
服务器方面
nginx 使用负载均衡
使用服务器集群
业务实现方面
使用队列Kafka、RabitMQ等
处理秒杀 抢购等高并发场景保证数据安全
使用缓存Redis、Memcache等
尽量使用缓存,包括用户缓存,信息缓存等,可以大量减少与数据库的交互,提高性能。
使用多线程
部分功能使用多线程后台执行 不阻塞主线程
数据库方面
优化数据库查询语句
优化数据库结构,多做索引,提高查询效率
统计相关功能最好定时统计,避免实时查询
代码方面
代码构造的时候尽量避免不必要的资源浪费,提高性能
如:不要频繁使用new对象 使用单例模式等
string的连接操作,使用stringbuffer(速度慢,线程安全)或者stringbuilder(速度快,线程不安全)
utility类型的类通过静态方法来访问
mybatis一级缓存(同一个SqlSession内),二级缓存(不同的SqlSession间,mapper)
- 一级缓存:mybatis每次在查询后,会将语句和参数相同的查询SQL的结果集存放进缓存,待下一次有相同的语句和参数时,mybatis直接将缓存内的结果集返回,而不再查询数据库。
- 二级缓存:需要手动开启。一级缓存在同一个SqlSession内,以SqlSession为缓存单位;二级缓存在不同的SqlSession间,以mapper为单位,不同的SqlSession间可以共享相同的mapper下接口查询的数据
docker (k8s)
docker-compose
参考博文:https://www.jianshu.com/p/7893af4976d9
JVM调优
XX:MetaspaceSize=128m (元空间默认大小)
XX:MaxMetaspaceSize=128m (元空间最大大小)
Xms1024m (堆最大大小)
Xmx1024m (堆默认大小)
Xmn256m (新生代大小)
Xss256k (棧最大深度大小)
XX:SurvivorRatio=8 (新生代分区比例 8:2)
XX:+UseConcMarkSweepGC (指定使用的垃圾收集器,这里使用CMS收集器)
XX:+PrintGCDetails (打印详细的GC日志)
参考博文:https://blog.youkuaiyun.com/sun1021873926/article/details/78002118
springcloud用过什么组件
- spring cloud eureka : 注册中心,可以看到各个服务运行状态,并且各个微服务调用都通过注册中心来找到内网ip进行调用
- spring cloud gateway:
对外的网关,分为zuul版本和F版本,两者最大区别是底层容器不同,zuul版本是servlet,F版本的是webFlux框架,并且F版本可设置统一过滤器,单个微服务过滤器,限流过滤器,相同的是都有负载均衡,熔断机制,重试规则 - spring cloud config: 配置中心,可以分为本地扫描配置和从git仓库拉取缓存,在spring cloud
bus的配合下,可实现实时动态刷新配置文件 - spring cloud bus: 消息总线z,实现各个微服务之间的通信,整合java消息的发送和接收
- spring cloud Ribbon: 负载均衡
- spring cloud Feign: PRC 远程服务调用
- spring cloud Hystrix: 熔断机制
- spring cloud zipkin: 链路追踪,分为http追踪和rabbitmq追踪,提供前端页面显示各个接口之间的复杂的互相调用
- spring boot admin:
显示各个服务运行的详细状态,线程池,内存环境,系统环境属性,spring各种bean运行状态,可以把阿里数据库连接池druid的监控结合到了监控页面,可以监控到各个sql执行时间等等 - spring cloud oauth2: 鉴权服务, 四种模式: 用户名密码模式, 客户端模式, 授权码模式,简化模式过于复杂.
说明一下,目前微服务一般是使用Spring Cloud Alibaba
阿里开源组件 - Nacos:一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
- Sentinel:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
- RocketMQ:开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
- Dubbo:这个就不用多说了,在国内应用非常广泛的一款高性能 Java RPC 框架。
- Seata:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
- Arthas:开源的Java动态追踪工具,基于字节码增强技术,功能非常强大。
CAP理论(C——数据一致性,A——服务可用性,P——服务对网络分区故障的容错性),
Euraka 和 dubbo ,zookeeper
- Euraka: 是分布式系统中的AP
- dubbo的注册中心一般选用zookeeper: zookeeper保证的是cp
- 在P在网络分区发生故障的时候,zookeeper 要进行选举,euraka: 可以快速切换到另外一个节点
java反射原理
jvm在运行过程中载入class文件,得到class对象后反向获取对象的各种信息
zookeeper 调用流程处理方法,调用方式
微服务调用元素
Java浅拷贝和深拷贝的理解和实现方式
浅拷贝(浅复制、浅克隆):
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。
换言之,浅拷贝仅仅复制所拷贝的对象,而不复制它所引用的对象。
深拷贝(深复制、深克隆):
被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。
换言之,深拷贝把要复制的对象所引用的对象都复制了一遍
java悲观锁和乐观锁区别
定义:
悲观锁(Pessimistic Lock):
每次获取数据的时候,都会担心数据被修改,所以每次获取数据的时候都会进行加锁,确保在自己使用的过程中数据不会被别人修改,使用完成后进行数据解锁。由于数据进行加锁,期间对该数据进行读写的其他线程都会进行等待。
乐观锁(Optimistic Lock):
每次获取数据的时候,都不会担心数据被修改,所以每次获取数据的时候都不会进行加锁,但是在更新数据的时候需要判断该数据是否被别人修改过。如果数据被其他线程修改,则不进行数据更新,如果数据没有被其他线程修改,则进行数据更新。由于数据没有进行加锁,期间该数据可以被其他线程进行读写操作。
适用场景:
悲观锁:比较适合写入操作比较频繁的场景,如果出现大量的读取操作,每次读取的时候都会进行加锁,这样会增加大量的锁的开销,降低了系统的吞吐量。
乐观锁:比较适合读取操作比较频繁的场景,如果出现大量的写入操作,数据发生冲突的可能性就会增大,为了保证数据的一致性,应用层需要不断的重新获取数据,这样会增加大量的查询操作,降低了系统的吞吐量。
总结:两种所各有优缺点,读取频繁使用乐观锁,写入频繁使用悲观锁。
后端实现跨域
- spring就用filter里面往header里面放跨域参数
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
- Springboot 很简单 @CrossOrigin
- 或者用nginx实现做代理
Spring Boot、Spring MVC、Spring之间的区别?(Spring Boot本质是什么?)
Spring Boot Starter 是什么?
如何自定义Spring Boot Starter?(如何扩展Spring Boot)
Spring Boot 的自动装配原理是什么?(源码分析哦)
在全局配置的属性如:server.port等,
通过@ConfigurationProperties注解,
绑定到对应的XxxxProperties配置实体类上封装为一个bean,
然后再通过@EnableConfigurationProperties注解导入到Spring容器中。
Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到
META-INF/spring.factories配置文件中的所有自动配置类,
并对其进行加载,而这些自动配置类 都是以AutoConfiguration结尾来命名的,
它实际上就是一个JavaConfig形式的Spring容器配置类,
它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:
server.port,
参考博文:https://blog.youkuaiyun.com/Dongguabai/article/details/80865599
Spring Boot 的启动流程是什么?
有没有看过 Spring Boot 源码?你觉得最神奇的地方是什么?谈谈理解,有哪些特性
springboot是用于快速开发spring应用的一个脚手架,设计目的就是为了简化spring应用的初始化搭建以及开发过程
1.springboot提供了starter结合自动配置,对主流框架无配置集成,开箱即用
2.springboot简化开发,采用javaconfig的方式可以使用零xml的方式进行开发
3.springboot内置web容器,直接jar包启动程序
4.springboot帮我管理了第三方依赖,减少版本冲突
5.springboot自带监控功能,可监控运行情况,或者内存,线程池,http请求统计等,同时提供可以优雅的关闭应用程序的功能
对服务注册中心的理解
我的理解很简单就是服务注册进来就把他记录下来,客户端需要用的时候就直接来查询
对网关的理解
为微服务架构提供一种简单且有效的 API 路由的管理方式,并基于 Filter 的方式提供网关的基本功能,例如说安全认证、监控、限流等等
注意:Spring Cloud Gateway会和spring-webmvc的依赖冲突,需要排除spring-webmvc
路由(route)
路由是网关中最基础的部分,路由信息包括一个ID、一个目的URI、一组断言工厂、一组Filter组成。如果断言为真,则说明请求的URL和配置的路由匹配。
断言(predicates)
Java8中的断言函数,SpringCloud
Gateway中的断言函数类型是Spring5.0框架中的ServerWebExchange。断言函数允许开发者去定义匹配Http
request中的任何信息,比如请求头和参数等。
过滤器(Filter)
SpringCloud Gateway中的filter分为Gateway FilIer和Global
Filter。Filter可以对请求和响应进行处理。
jvm 原理
- JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器。它是一种利用软件方法实现的抽象的计算机基于下层的操作系统和硬件平台,可以在上面执行java的字节码程序。
- java编译器只要面向JVM,生成JVM能理解的代码或字节码文件。Java源文件经编译成字节码程序,通过JVM将每一条指令翻译成不同平台机器码,通过特定平台运行。
你是怎么设计微服务
1·单一职责(Single Responsibility),一个服务应当承担尽可能单一的职责,服务应基于有界的上下文(bounded context,通常是边界清晰的业务领域)构建,服务理想应当只有一个变更的理由(类似Robert C. Martin讲的:A class should have only one reason to change),当一个服务承担过多职责,就会产生各种耦合性问题,需要进一步拆分使其尽可能职责单一化。
2·关注分离(Separation of Concerns),跨横切面逻辑,例如日志分析、监控、限流、安全等等,尽可能与具体的业务逻辑相互分离,让开发人员能专注于业务逻辑的开发,减轻他们的思考负担,这个也是有界上下文(bounded context)的一个体现。
3·模块化(Modularity)和分而治之(Divide & Conquer),这个是解决复杂性问题的一般性方法,将大问题(如单块架构)大而化小(模块化和微服务化),然后分而治之。
前期阶段,大致要做好如下事情:
和多方充分沟通,确保能符合客户和组织的需求,并且得到认同
和团队沟通,让队友(开发/测试/运维)理解,并且积极投入
和业务部门沟通,指定版本计划和上线时间
设计阶段,参考 Sam Newman 的著作《微服务设计》,单微服务必须要满足以下的条件,才符合微服务的基本要求:
标准的 REST 风格接口(基于 HTTP 和 JSON 格式)
独立部署,避免共享数据库(避免因为数据库而影响整个分布式系统)
业务上的高内聚,减少依赖(从设计上要避免服务过大或者太小)
技术阶段,庞大的分布式系统,需要强大基础设施来支撑,微服务涉及哪些基础设施?
CI/CD和自动化(分布式系统几乎不可能通过人工手动发布)
虚拟化技术(要保证微服务运行环境隔离,目前行业主流的是使用 Docker 容器)
日志聚合,全链路监控(高度可观察和分析诊断问题)
参考博文:https://www.cnblogs.com/xiao2shiqi/p/11298663.html
redis用过锁吗
redis缓存穿透
key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。
- 解决方案:
如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。
参考博文: https://www.cnblogs.com/xichji/p/11286443.html
redis雪崩
缓存雪崩很形象了,就是大量key没了,请求像雪崩一样打到数据库;
- 解决方案:
1.很多key在同一时间同时过期,解决方案就是把key分组,分别设置过期时间,避免同时过期的情况
2.失效时间上加上一个随机值,比如1-5分钟随机
缓存击穿
缓存击穿也挺形象,就是单个key没了,但是它是热点,redis这个盾没防住,大量针对一个key的请求像剑一样刺向数据库;
-
解决方案:
1、上面说过了,如果业务允许的话,对于热点的key可以设置永不过期的key。
2、使用互斥锁。如果缓存失效的情况,只有拿到锁才可以查询数据库,降低了在同一时刻打在数据库上的请求,防止数据库打死。当然这样会导致系统的性能变差。缓存穿透就很好理解了, 穿透了嘛,数据库里也没这个数据,连数据库也一起透心凉心飞扬
redis内存优化
参考:https://blog.youkuaiyun.com/qq_42046105/article/details/124507123
redis淘汰策略
(1)volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰。
(2)volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰。
(3)volatile-random:从已设置过期时间的数据集中任意选择数据淘汰。
(4)volatile-lfu:从已设置过期时间的数据集挑选使用频率最低的数据淘汰。
(5)allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
(6)allkeys-lfu:从数据集中挑选使用频率最低的数据淘汰。
(7)allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
(8) no-enviction(驱逐&#x