精华内容
下载资源
问答
  • Java面试宝典

    万次阅读 多人点赞 2018-11-10 23:49:18
    Java 基础-------------------------------------------------------------------------------------------------- 1 基本数据类型----------------------------------------------------------------------------...

    Java 基础-------------------------------------------------------------------------------------------------- 1

    基本数据类型--------------------------------------------------------------------------------------------- 1

    包装类型--------------------------------------------------------------------------------------------------- 1

    集合--------------------------------------------------------------------------------------------------------- 2

    多线程------------------------------------------------------------------------------------------------------ 2

    生命周期--------------------------------------------------------------------------------------------------- 2

    热门面试问题:------------------------------------------------------------------------------------------ 3

    1、什么是 GC?为什么要有 GC--------------------------------------------------------------------- 3

    2、final, finally 和 finalize 的区别?----------------------------------------------------------------- 3

    3、什么是单例模式?实现步骤----------------------------------------------------------------------- 3

    4、ArrayList 和 LinkedList 有何区别?------------------------------------------------------------- 3

    5、HashMap 和 Hashtable 的区别?--------------------------------------------------------------- 3

    6、Iterater 和 ListIterator 之间有什么区别?------------------------------------------------------ 4

    7、创建线程的方式?----------------------------------------------------------------------------------- 4

    8、什么是死锁?----------------------------------------------------------------------------------------- 4

    9、wait()与 sleep()的区别?--------------------------------------------------------------------------- 4

    10、什么是 ThreadLocal?ThreadLocal 和 Synchonized 的区别?------------------------- 4

    Java Web--------------------------------------------------------------------------------------------------- 5

    Ajax---------------------------------------------------------------------------------------------------------- 5

    JQuery ------------------------------------------------------------------------------------------------------5

    Cookie------------------------------------------------------------------------------------------------------ 5

    Session----------------------------------------------------------------------------------------------------- 6

    热门面试问题:------------------------------------------------------------------------------------------- 6

    1、原生态 Ajax 执行流程?---------------------------------------------------------------------------- 6

    2、转发(forward)和重定向(redirect)的区别?---------------------------------------------- 6

    3、怎么防止表单重复提交?--------------------------------------------------------------------------- 7

    4、web.xml 文件中可以配置哪些内容?------------------------------------------------------------ 7

    数据库(MySQL) ----------------------------------------------------------------------------------------7

    连接查询----------------------------------------------------------------------------------------------------- 7
    内连接-------------------------------------------------------------------------------------------------------- 7

    外连接-------------------------------------------------------------------------------------------------------- 7

    联合查询----------------------------------------------------------------------------------------------------- 8

    索引----------------------------------------------------------------------------------------------------------- 9

    数据库引擎-------------------------------------------------------------------------------------------------- 9

    存储过程----------------------------------------------------------------------------------------------------- 9

    热门面试问题:------------------------------------------------------------------------------------------- 10

    1、JDBC 编程的步骤?--------------------------------------------------------------------------------- 10

    2、事务的 ACID 是什么?事务并发会产生哪些问题?------------------------------------------ 10

    3、数据库性能优化有哪些方式?--------------------------------------------------------------------- 10

    框架部分----------------------------------------------------------------------------------------------------- 11

    Spring-------------------------------------------------------------------------------------------------------- 11

    Spring 的理解----------------------------------------------------------------------------------------------- 11

    Spring Bean 生命周期------------------------------------------------------------------------------------ 12

    Spring 中的设计模式-------------------------------------------------------------------------------------- 12

    Spring 注解-------------------------------------------------------------------------------------------------- 12

    Spring 事务-------------------------------------------------------------------------------------------------- 13

    SpringMVC-------------------------------------------------------------------------------------------------- 14

    SpringMVC 执行流程------------------------------------------------------------------------------------- 14

    springmvc 常用注解--------------------------------------------------------------------------------------- 14

    SpringMVC 和 Struts2 对比----------------------------------------------------------------------------- 15

    Mybatis -------------------------------------------------------------------------------------------------------15

    Mybatis 的理解--------------------------------------------------------------------------------------------- 15

    Mybatis 缓存 ------------------------------------------------------------------------------------------------16

    SpringBoot-------------------------------------------------------------------------------------------------- 16

    SpringBoot 简介------------------------------------------------------------------------------------------- 16

    SpringBoot 特性 -------------------------------------------------------------------------------------------16

    SpringBoot 核心 -------------------------------------------------------------------------------------------16

    SpringCloud ------------------------------------------------------------------------------------------------17

    SpringCloud 简介 -----------------------------------------------------------------------------------------17

    SpringCloud 核心组件 -----------------------------------------------------------------------------------17
    微服务 -------------------------------------------------------------------------------------------------------17

    Docker -------------------------------------------------------------------------------------------------------17

    Docker 简介 ------------------------------------------------------------------------------------------------17

    Docker 理解 ------------------------------------------------------------------------------------------------17

    Redis ---------------------------------------------------------------------------------------------------------24

    Redis 简介 --------------------------------------------------------------------------------------------------24

    Redis 支持的数据类型 -----------------------------------------------------------------------------------24

    Redis 应用场景 --------------------------------------------------------------------------------------------24

    Redis 持久化 -----------------------------------------------------------------------------------------------24

    Redis 的优势 -----------------------------------------------------------------------------------------------24

    Solr -----------------------------------------------------------------------------------------------------------25

    Solr 简介 ----------------------------------------------------------------------------------------------------25

    Solr 配置 ----------------------------------------------------------------------------------------------------25

    倒排索引 ----------------------------------------------------------------------------------------------------25

    RabbitMQ/ActiveMQ -------------------------------------------------------------------------------------26

    RabbitMQ 简介 --------------------------------------------------------------------------------------------26

    RabbitMQ 特点 --------------------------------------------------------------------------------------------26

    RabbitMQ 工作模式 --------------------------------------------------------------------------------------26

    ActiveMQ 简介 ---------------------------------------------------------------------------------------------27

    ActiveMQ 工作模式 ---------------------------------------------------------------------------------------27
    MQ 对比 -----------------------------------------------------------------------------------------------------27

    Dubbo --------------------------------------------------------------------------------------------------------27

    Dubbo 简介 -------------------------------------------------------------------------------------------------27

    Dubbo 开发流程 -------------------------------------------------------------------------------------------28

    FastDFS -----------------------------------------------------------------------------------------------------28

    FastDFS 简介 ----------------------------------------------------------------------------------------------28

    文件上传流程 -----------------------------------------------------------------------------------------------29

    Nginx ---------------------------------------------------------------------------------------------------------29

    Nginx 简介 --------------------------------------------------------------------------------------------------29

    Nginx 功能 --------------------------------------------------------------------------------------------------29

    Quartz -------------------------------------------------------------------------------------------------------30

    Quartz 简介 ------------------------------------------------------------------------------------------------30

    Quartz 核心元素 ------------------------------------------------------------------------------------------30

    数据库笔试题 ----------------------------------------------------------------------------------------------31

    用一条 SQL 语句查询出每门课都大于 80 分的学生姓名 ---------------------------------------31

    所有球队之间的比赛组合 -------------------------------------------------------------------------------31

    显示文章标题,发帖人、最后回复时间 -------------------------------------------------------------31

    航空网的几个航班查询题 -------------------------------------------------------------------------------32


    Java 基础

    基本数据类型:

    在这里插入图片描述

    包装类型:

    包装类型是对基本数据类型不足之处的补充。

    基本数据类型的传递方式是值传递,而包装类型是引用传递,同时提供了很多数据类型间转换的方法。

    Java1.5 以后可以自动装箱和拆箱。

    集合

    在这里插入图片描述

    List:有序、可重复。可以通过索引快速查找,但进行增删操作时后续的数据需要移动,所以增删速度慢。

    Set:无序、不可重复。

    Map:键值对、键唯一、值不唯一。Map 集合中存储的是键值对,键不能重复,值可以重复。根据键得到值,对 map 集合遍历时先得到键的 set 集合,对 set 集合进行遍历,得到相应的值。

    多线程

    在这里插入图片描述

    新建状态: 一个新产生的线程从新状态开始了它的生命周期。它保持这个状态直到程序 start 这个线程。

    运行状态:当一个新状态的线程被 start 以后,线程就变成可运行状态,一个线程在此状态下被认为是开始执行其任务

    就绪状态:当一个线程等待另外一个线程执行一个任务的时候,该线程就进入就绪状态。当另一个线程给就绪状态的线程发送信号时,该线程才重新切换到运行状态。

    休眠状态: 由于一个线程的时间片用完了,该线程从运行状态进入休眠状态。当时间间隔到期或者等待的时间发生了,该状态的线程切换到运行状态。

    终止状态: 一个运行状态的线程完成任务或者其他终止条件发生,该线程就切换到终止状态。


    热门面试问题:

    1、什么是 GC?为什么要有 GC?

    GC(Garbage Collection)是垃圾收集的意思,负责清除对象并释放内存。Java 提供的 GC 功能可以自动检测对象是否超过作用域从而达到自动回收内存的目的,从而防止内存泄漏。

    2、final, finally 和 finalize 的区别?

    final 用于声明属性,方法和类,表示属性不可变,方法不可被重写,类不可被继承。

    finally 是异常处理语句结构的一部分,表示总是执行。

    finalize 是 object 类的一个方法,在垃圾收集器执行的时候会调用这个对象回收的方法,工垃圾收集时其他资源的回收,比如关闭文件。

    3、什么是单例模式?实现步骤?

    单例模式保证了对象唯一。分为懒汉式(在类加载时不初始化)和饿汉式(在类加载时就完成了初始化,所以类加载比较慢,但获取对象的速度快)。

    实现步骤:私有化构造函数、创建一个静态的私有对象、提供公共的访问方法。

    4、ArrayList 和 LinkedList 有何区别?

    ArrayList 是基于动态数组的数据结构,LinkedList 是基于链表的数据结构;对于随机访问 get 和 set,ArrayList 较优,因为 LinkedList 要移动指针;对于新增和删除操作 add 和 remove,LinedList 较优,因为ArrayList 要移动数据。

    5、HashMap 和 Hashtable 的区别?

    HashMap 允许空键值,Hashtable 不允许;

    HashMap 继承自 AbstractMap,Hashtable 继承自 Dictionary 类,两者都实现了 Map 接口; HashMap 的方法不是同步的,Hashtable 的方法是同步的。

    6、Iterater 和 ListIterator 之间有什么区别?

    Iterator 用来遍历 Set 和 List 集合,而 ListIterator 只能遍历 List; Iterator 只可以向前遍历,而 LIstIterator 可以双向遍历;ListIterator 从 Iterator 接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。

    7、创建线程的方式?

    继承 Thread 类

    实现 Runnable 接口

    使用 Executor 框架

    8、什么是死锁?

    两个线程或两个以上线程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是这些线程都陷入了无限的等待中。

    9、wait()与 sleep()的区别?

    sleep()来自 Thread 类,wait()来自 Object 类;

    调用 sleep()方法,线程不会释放对象锁。而调用 wait 方法线程会释放对象锁;

    sleep()睡眠后不出让系统资源,wait 让其他线程可以占用 CPU;

    sleep(milliseconds)需要指定一个睡眠时间,时间一到会自动唤醒。而 wait()需要配合 notify()

    或者 notifyAll()使用。

    10、什么是 ThreadLocal?ThreadLocal 和 Synchonized 的区别?

    线程局部变量。是局限于线程内部的变量,属于线程自身所有,不在多个线程间共享。Java提供 ThreadLocal 类来支持线程局部变量,是一种实现线程安全的方式。

    synchronized 是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而 ThreadLocal 为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。


    Java Web

    Ajax

    AJAX = Asynchronous JavaScript and XML(异步 JavaScript 和 XML)。

    Ajax 的原理简单来说通过 XmlHttpRequest 对象来向服务器发异步请求,从服务器获得数据,然后用 Javascript 来操作 DOM 而更新页面。这其中最关键的一步就是从服务器获得请求数据。

    XmlHttpRequest 是 ajax 的核心机制,它是在 IE5 中首先引入的,是一种支持异步请求的技术。简单的说,也就是 Javascript 可以及时向服务器提出请求和处理响应,而不阻塞用户。达到无刷新的效果。
    在这里插入图片描述

    JQuery

    JQuery 是一个 JavaScript 库。功能包括 HTML 元素选取和操作、CSS 操作、HTML 事件函数、 JavaScript 特效和动画、HTML DOM 遍历和修改、AJAX 和 Utilities。除此之外,JQuery 还提供了大量插件。

    基础语法: $(selector).action()。

    选择器:主要分四大选择器,分别是基本选择器、层次选择器、过滤选择器、属性过滤选择器。

    事件:例如 click()、dblclick()、mouseenter()、mouseleave()、mousedown()等。

    Cookie

    在 web 程序中是使用 HTTP 协议来传输数据的,因为 http 是无状态协议,一旦数据交换完毕,客户端和服务器端的连接就会关闭,再次交换数据需要建立新的连接,所以无法实现会话跟踪,cookie 技术则弥补了这一缺陷。

    cookie 实际上一段的文本信息,客户端请求服务器。如果服务器需要记录该用户的状态,就使用 response 向客户端浏览器颁发一个 cookie。客户端浏览器会把 cookie 保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该 cookie 一同提交给服务器。服务器检查该 cookie,以此来辨认用户的状态。服务器还可以根据需要修改 cookie 的内容。
    cookie 生命周期:

    cookie 的 maxAge 决定 cookie 的生命周期,单位为秒(second)。cookie 通过 getMaxAge() 方法和 setMaxAge()方法来获得 maxAge 属性,如果 maxAhe 属性为正,则表示 cookie 会在 maxAge 秒之后自动失效。如果 maxAge 属性为负,则说明 cookie 仅在本浏览器窗口和本窗口打开的子窗口下有效,关闭窗口 cookie 则失效。maxAge 的默认值是-1 当 maxAge 的值为 0 时,表示删除 cookie。

    Session

    session 也是一种记录客户状态的机制,不同的是 cookie 保存在客户端浏览器中,而 session 保存在服务器上。客户端浏览器访问服务器是时候把客户端信息以某种形式记录在服务器上,这就是 session 中查找该客户的状态。

    session 生命周期:

    session 保存在服务器端,为了获得更高的存取速度,服务器一般把 session 放在内存。每个用户都会有一个独立的 session,如果 session 内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。

    session 在用户第一次访问服务器的时候自动创建,需要注意只有访问 JSP,Servlet 等程序时才会创建 session;只要访问 HTML、IMAGE 等静态资源不会创建 session。如果尚未生成session,可以使用 request.getSession(true)强制生成 session。

    session 生成后,只要用户访问,服务器就会更新 session 的最后访问时间,并维护该 session。用户每访问服务器一次,无论是否续写 session 服务器都认为该用户的 session 活跃(active)了一次。

    Session 对应的类是 javax.servlet.http.HttpSession,每一个访问者都对应一个 session 对象,并将其状态信息保存在这个 session 对象中,session 对象的创建是在用户第一次访问服务器时产生的。


    热门面试问题:

    1、原生态 Ajax 执行流程?

    创建 XMLHttpRequest 对象;

    注册回调函数;

    设置连接信息;

    发送数据,与服务器开始交互;

    接受服务器返回数据。

    2、转发(forward)和重定向(redirect)的区别?

    forward 是容器中控制权的转向,是服务器请求资源,服务器直接访问目标地址的 URL,把那个 URL 的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。

    redirect 就是服务器端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,因此从浏览器的地址栏中可以看到跳转后的链接地址,很明显 redirect 无法访问到服务器保护起来资源,但是可以从一个网站 redirect 到其他网站。

    3、怎么防止表单重复提交?

    i.禁掉提交按钮。表单提交后使用 Javascript 使提交按钮 disable。

    ii.Post/Redirect/Get 模式。在提交后执行页面重定向,这就是所谓的 Post-Redirect-Get (PRG) 模式。简言之,当用户提交了表单后,你去执行一个客户端的重定向,转到提交成功信息页面。

    iii.在 session 中存放一个特殊标志。当表单页面被请求时,生成一个特殊的字符标志串,存在 session 中,同时放在表单的隐藏域里。接受处理表单数据时,检查标识字串是否存在,并立即从 session 中删除它,然后正常处理数据。

    4、web.xml 文件中可以配置哪些内容?

    web.xml 用于配置 Web 应用的相关信息,如:监听器(listener)、过滤器(filter)、 Servlet、相关参数、会话超时时间、安全验证方式、错误页面等。


    数据库(MySQL)

    连接查询

    分类:内连接、外连接、自然连接(略)、交叉连接(略)。

    内连接

    基本语法:左表 [inner] join 右表 on 左表.字段 = 右表.字段;

    从左表中取出每一条记录,去右表中与所有的记录进行匹配:匹配必须是某个条件在左表中与右表中相同最终才会保留结果,否则不保留。

    外连接

    基本语法: 左表 left/right join 右表 on 左表.字段 = 右表.字段;

    left join: 左外连接(左连接), 以左表为主表

    right join: 右外连接(右连接), 以右表为主表

    以某张表为主,取出里面的所有记录,然后每条与另外一张表进行连接:不管能不能匹配上条件,最终都会保留。能匹配,正确保留;不能匹配,其他表的字段都置空 NULL。
    在这里插入图片描述
    左外连接在这里插入图片描述
    右外连接在这里插入图片描述

    联合查询

    基本语法:

    		Select 语句 1
    		
    		Union [union 选项]
    		
    		Select 语句 2
    		
    		……
    
    

    将多次查询(多条 select 语句), 在记录上进行拼接(字段不会增加),每一条 select 语句获取的字段数必须严格一致(但是字段类型无关)。

    其中 union 选项有 2 个。ALL:保留所有;Distinct(默认):去重。

    应用:查询同一张表,但是有不同的需求;查询多张表,多张表的结构完全一致,保存的数据也是一样的。

    在联合查询中,order by 不能直接使用。需要对查询语句使用括号才行。另外需要配合 limit 使用。

    索引

    如果说数据库表中的数据是一本书,那么索引就是书的目录。索引能够让我们快速的定位想要查询的数据。

    索引的结构:BTree 索引和 Hash 索引。

    MyISAM 和 InnoDB 存储引擎:只支持 BTREE 索引, 也就是说默认使用 BTREE,不能够更换。

    MEMORY/HEAP 存储引擎:支持 HASH 和 BTREE 索引。

    索引的分类:单列索引(普通索引,唯一索引,主键索引)、组合索引、全文索引、空间索引。

    数据库引擎

    InnoDB:支持事务处理,支持外键,支持崩溃修复能力和并发控制。如果需要对事务的完整

    性要求比较高(比如银行),要求实现并发控制(比如售票),那选择 InnoDB 有很大的优势。

    如果需要频繁的更新、删除操作的数据库,也可以选择 InnoDB,因为支持事务的提交(commit)

    和回滚(rollback)。

    MyISAM:插入数据快,空间和内存使用比较低。如果表主要是用于插入新记录和读出记录,

    那么选择 MyISAM 能实现处理高效率。如果应用的完整性、并发性要求比较低,也可以使

    用。

    MEMORY:所有的数据都在内存中,数据的处理速度快,但是安全性不高。如果需要很快的

    读写速度,对数据的安全性要求较低,可以选择 MEMOEY。它对表的大小有要求,不能建

    立太大的表。所以,这类数据库只使用在相对较小的数据库表。

    存储过程

    SQL 语句需要先编译然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的 SQL 语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它。

    存储过程是可编程的函数,在数据库中创建并保存,可以由 SQL 语句和控制结构组成。当想要在不同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的。数据库中的存储过程可以看做是对编程中面向对象方法的模拟,它允许控制数据的访问方式。

    存储过程的优点:
    增强 SQL 语言的功能和灵活性;
    标准组件式编程;
    较快的执行速度;
    减少网络流量;
    作为一种安全机制来充分利用。


    热门面试问题:

    1、JDBC 编程的步骤?

    (1) 注册驱动;

    (2) 获取连接对象 Connection;

    (3) 创建 Statement 对象;

    (4) 运行 SQL 语句;

    (5) 处理结果;

    (6) 关闭连接释放资源。

    2、事务的 ACID 是什么?事务并发会产生哪些问题?

    ACID 表示事务的特性:原子性、一致性、隔离性和持久性。

    • 原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败;

    • 一致性(Consistent):事务结束后系统状态是一致的;

    • 隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态;

    • 持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败。通过日志和同步备份可以在故障发生后重建数据。

    事务并发产生的问题:脏读、幻读、不可重复读。

    脏读(Dirty Read):A 事务读取 B 事务尚未提交的数据并在此基础上操作,而 B 事务执行回滚,那么 A 读取到的数据就是脏数据。

    幻读(Phantom Read):事务 A 重新执行一个查询,返回一系列符合查询条件的行,发现其中插入了被事务 B 提交的行。

    不可重复读(Unrepeatable Read):事务 A 重新读取前面读取过的数据,发现该数据已经被另一个已提交的事务 B 修改过了。

    3、数据库性能优化有哪些方式?
    SQL 优化:
    		尽量避免使用 SELECT	*;
    		只查询一条记录时使用 limit 1;
    		使用连接查询代替子查询;
    		尽量使用一些能通过索引查询的关键字。
    表结构优化:
    
    		尽量使用数字类型字段,提高比对效率;
    		长度不变且对查询速度要求高的数据可以考虑使用 char,否则使用 varchar;表中字段过多时可以适当的进行垂直分割,将部分字段移动到另外一张表;表中数据量过大可以适当的进行水平分割,将部分数据移动到另外一张表。
    
    其它优化:
    
    		对查询频率高的字段适当的建立索引,提高效率;根据表的用途使用合适的数据库引擎;读写分离。		
    
    

    框架部分

    Spring

    Spring 的理解

    spring 是一个开源框架,Spring 为简化企业级应用开发而生,使用 Spring 可以使简单的 JavaBean 实现以前只有 EJB 才能实现的功能。Spring 是一个 IOC 和 AOP 容器框架。 Spring 主要核心是:

    (1)控制反转(IOC):传统的 java 开发模式中,当需要一个对象时,我们会自己创建一个对象,而在 Spring 开发模式中,Spring 容器使用了工厂模式为我们创建了所需要的对象,我们直接调用 Spring 为我们提供的对象即可,这就是控制反转的思想。实例化一个 java 对象有三种方式:使用类构造器,使用静态工厂方法,使用实例工厂方法。当使用 spring 时我们不需要关心通过何种方式实例化一个对象,spring 通过控制反转机制自动为我们实例化一个对象。

    (2)依赖注入(DI):Spring 使用 Java Bean 对象的 Set 方法或者带参数的构造方法为我们在创建所需对象时将其属性自动设置所需要的值的过程就是依赖注入的基本思想。

    (3)面向切面编程(AOP):在面向对象编程(OOP)思想中,我们将事物纵向抽象成一个个的对象。而在面向切面编程中,我们将一个个对象某些类似的方面横向抽象成一个切面,对这个切面进行一些如权限验证,事物管理,记录日志等公用操作处理的过程就是面向切面编程的思想。

    在 Spring 中,所有管理的对象都是 JavaBean 对象,而 BeanFactory 和 ApplicationContext 就是 spring 框架的两个 IOC 容器,现在一般使用 ApplicationContext,其不但包含了 BeanFactory 的作用,同时还进行更多的扩展。

    Spring Bean 生命周期

    1.Spring 容器 从 XML 文件中读取 Bean 的定义,并实例化 Bean。

    2.Spring 根据 Bean 的定义填充所有的属性。

    3.如果 Bean 实现了 BeanNameAware 接口,Spring 传递 bean 的 ID 到 setBeanName 方法。

    4.如果 Bean 实现了 BeanFactoryAware 接口, Spring 传递 beanfactory 给 setBeanFactory 方法。

    5.如 果 有 任 何 与 bean 相 关 联 的 BeanPostProcessors , Spring 会 在postProcesserBeforeInitialization()方法内调用它们。

    6.如果 bean 实现 IntializingBean 了,调用它的 afterPropertySet 方法,如果 bean 声明了初始化方法,调用此初始化方法。

    7.如果有 BeanPostProcessors 和 bean 关联,这些 bean 的 postProcessAfterInitialization()

    方法将被调用。

    8.如果 bean 实现了 DisposableBean,它将调用 destroy()方法。注意:

    有两个重要的 bean 生命周期方法,第一个是 setup() , 它是在容器加载 bean 的时候被调用。第二个方法是 teardown() 它是在容器卸载类的时候被调用。

    The bean 标签有两个重要的属性 init-method 和 destroy-method。使用它们你可以自己定制初始化和注销方法。它们也有相应的注解@PostConstruct 和@PreDestroy。

    Spring 中的设计模式

    代理模式—Spring 中两种代理方式,若目标对象实现了若干接口,spring 使用 JDK 的 java.lang.reflect.Proxy 类代理,若目标对象没有实现任何接口,spring 使用 CGLIB 库生成目标对象的子类。

    单例模式—在 spring 配置文件中定义的 bean 默认为单例模式。

    模板方法模式—用来解决代码重复的问题。比如: RestTemplate, JmsTemplate, JpaTemplate。

    前端控制器模式—Srping 提供了 DispatcherServlet 来对请求进行分发。

    视图帮助(View Helper )—Spring 提供了一系列的 JSP 标签,高效宏来辅助将分散的代码整合在视图里。

    依赖注入—贯穿于 BeanFactory/ApplicationContext 接口的核心理念。

    工厂模式—在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。Spring 中使用 BeanFactory 用来创建对象的实例。

    Spring 注解

    Spring 在 2.5 版本以后开始支持用注解的方式来配置依赖注入。可以用注解的方式来替代 XML 方式的 bean 描述,可以将 bean 描述转移到组件类的内部,只需要在相关类上、方法上或者字段声明上使用注解即可。注解注入将会被容器在 XML 注入之前被处理,所以后者会覆盖掉前者对于同一个属性的处理结果。

    注解装配在 Spring 中是默认关闭的。所以需要在 Spring 文件中配置一下才能使用基于注解的装配模式。如果你想要在你的应用程序中使用关于注解的方法的话,请参考如下的配置。

    <beans>
    
    <context:annotation-config/>
    
    <!-- bean definitions go here -->
    
    </beans>
    

    context:annotation-config/标签配置完成以后,就可以用注解的方式在 Spring 中向属

    性、方法和构造方法中自动装配变量。

    几种比较重要的注解类型:

    1.@Required:该注解应用于设值方法。

    2.@Autowired:该注解应用于有值设值方法、非设值方法、构造方法和变量。

    3.@Qualifier:该注解和@Autowired 注解搭配使用,用于消除特定 bean 自动装配的歧义。

    4.JSR-250 Annotations: Spring 支持基于 JSR-250 注解的以下注解,@Resource、 @PostConstruct 和 @PreDestroy。

    Spring 事务

    Spring 支持两种类型的事务管理:

    1.编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。

    2.声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和 XML 配置来管理事务。

    Spring 事务配置示例(使用 tx 标签配置的拦截器)

    <!-- 定义事务管理器(声明式的事务) -->
    
    <bean id="transactionManager"
    
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    
    <property name="sessionFactory" ref="sessionFactory" />
    
    </bean>
    
    <!-- 配置 Advice 通知 -->
    
    <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes>
    
    <tx:method name="*" propagation="REQUIRED" /> </tx:attributes>
    
    </tx:advice>
    
    <!-- 配置切点切面 -->
    
    <aop:config>
    
    <aop:pointcut id="interceptorPointCuts" expression="execution(* com.bluesky.spring.dao.*.*(..))" />
    
    <aop:advisor advice-ref="txAdvice"
    
    pointcut-ref="interceptorPointCuts" />
    
    </aop:config>
    
    

    SpringMVC

    SpringMVC 执行流程

    在这里插入图片描述
    1、用户发送请求至 DispatcherServlet(前端控制器);

    2、DispatcherServlet 收到请求调用 HandlerMapping(处理器映射器);

    3、HandlerMapping 找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet;

    4、DispatcherServlet 调用 HandlerAdapter(处理器适配器);

    5、HandlerAdapter 经过适配调用具体的 Controller (处理器,也叫后端控制器);

    6、Controller 执行完成返回 ModelAndView 对象;

    7、HandlerAdapter 将 controller 执行结果 ModelAndView 返回给 DispatcherServlet;

    8、DispatcherServlet 将 ModelAndView 传给 ViewReslover(视图解析器);

    9、ViewReslover 解析后返回具体 View;

    10、DispatcherServlet 根据 View 进行渲染视图(即将模型数据填充至视图中);

    11、DispatcherServlet 响应用户。

    springmvc 常用注解

    @RequestMapping:是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

    @PathVariable:用于将请求 URL 中的模板变量映射到功能处理方法的参数上,即取出 uri 模板中的变量作为参数。

    @requestParam : 主 要 用 于 在 SpringMVC 后 台 控 制 层 获 取 参 数 , 类 似 一 种 是request.getParameter(“name”),它有三个常用参数:defaultValue = “0”, required = false, value = “isApp”;defaultValue 表示设置默认值,required 铜过 boolean 设置是否是必须要传入的参数,value 值表示接受的传入的参数类型。

    @ResponseBody : 该 注 解 用 于 将 Controller 的 方 法 返 回 的 对 象 , 通 过 适 当 的HttpMessageConverter 转换为指定格式后,写入到 Response 对象的 body 数据区。使用时机:返回的数据不是 html 标签的页面,而是其他某种格式的数据时(如 json、xml 等)使用 @RequestBody : 该 注 解 常 用 来 处 理 Content-Type: 不 是 application/x-www-form-urlencoded 编码的内容,例如 application/json, application/xml 等; @RequestHeader :可以把 Request 请求 header 部分的值绑定到方法的参数上。

    @CookieValue :可以把 Request header 中关于 cookie 的值绑定到方法的参数上。

    SpringMVC 和 Struts2 对比

    机制:spring mvc 的入口是 servlet,而 struts2 是 filter(这里要指出,filter 和 servlet 是不同的。以前认为 filter 是 servlet 的一种特殊),这样就导致了二者的机制不同,这里就牵涉到 servlet 和 filter 的区别了。

    性能:spring 会稍微比 struts 快。spring mvc 是基于方法的设计,而 sturts 是基于类,每次发一次请求都会实例一个 action,每个 action 都会被注入属性,而 spring 基于方法,粒度更细,但要小心把握像在 servlet 控制数据一样。spring3 mvc 是方法级别的拦截,拦截到方法后根据参数上的注解,把 request 数据注入进去,在 spring3 mvc 中,一个方法对应一个 request 上下文。而 struts2 框架是类级别的拦截,每次来了请求就创建一个 Action,然后调用 setter getter 方法把 request 中的数据注入;struts2 实际上是通过 setter getter 方法与 request 打交道的;struts2 中,一个 Action 对象对应一个 request 上下文。

    参数传递:struts 是在接受参数的时候,可以用属性来接受参数,这就说明参数是让多个方法共享的。

    设计思想上:struts 更加符合 oop 的编程思想,spring 就比较谨慎,在 servlet 上扩展。

    Mybatis

    Mybatis 的理解

    MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手工设置参数以及抽取结果集。MyBatis 使用简单的 XML 或注解来配置和映射基本体,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录。

    Mybatis 的优点:

    1、简单易学。mybatis 本身就很小且简单。没有任何第三方依赖,最简单安装只要两个 jar 加配置几个 sql 映射文件,易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现;

    2、灵活。mybatis 不会对应用程序或者数据库的现有设计强加任何影响。 sql 写在 xml 里,便于统一管理和优化。通过 sql 基本上实现不使用数据访问框架可以实现的所有功能;

    3、解除 sql 与程序代码的耦合。通过提供 DAO 层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql 和代码的分离,提高了可维护性;4、提供映射标签,支持对象与数据库的 orm 字段关系映射;5、提供对象关系映射标签,支持对象关系组建维护;

    6、提供 xml 标签,支持编写动态 sql。

    Mybatis 缓存

    一级缓存:Mybatis 的一级缓存的作用域是 session,当 openSession()后,如果执行相同的SQL(相同语句和参数),Mybatis 不进行执行 SQL,而是从缓存中命中返回。

    二级缓存:Mybatis 的二级缓存的作用域是一个 mapper 的 namespace,同一个 namespace 中查询 sql 可以从缓存中命中。二级缓存是可以跨 session 的。

    SpringBoot

    SpringBoot 简介

    Spring Boot(英文中是“引导”的意思),是用来简化 Spring 应用的搭建到开发的过程。应用开箱即用,只要通过 “just run”(可能是 java -jar 或 tomcat 或 maven 插件 run 或 shell 脚本),就可以启动项目。二者,Spring Boot 只要很少的 Spring 配置文件(例如那些 xml,property)。因为“习惯优先于配置”的原则,使得 Spring Boot 在快速开发应用和微服务架构实践中得到广泛应用。

    SpringBoot 特性

    自动配置:针对很多 Spring 应用程序常见的应用功能,Spring Boot 能自动提供相关配置;起步依赖:告诉 Spring Boot 需要什么功能,它就能引入需要的库;

    命令行界面:这是 Spring Boot 的可选特性,借此你只需写代码就能完成完整的应用程序,无需传统项目构建;

    Actuator:让你能够深入运行中的 Spring Boot 应用程序,一探究竟。

    SpringBoot 核心

    @SpringBootApplication 这个 Spring Boot 核心注解是由其它三个重要的注解组合,分别是:

    @SpringBootConfiguration 、 @EnableAutoConfiguration 和 @ComponentScan。

    @ SpringBootConfiguration

    点开查看发现里面还是应用了@Configuration。任何一个标注了@Configuration 的 Java 类定义的都是一个 JavaConfig 配置类。SpringBoot 社区推荐使用基于 JavaConfig 的配置形式,所以,这里的启动类标注了@Configuration 之后,本身其实也是一个 IoC 容器的配置类。

    @EnableAutoConfiguration

    是一个复合注解。最重要的是@Import(EnableAutoConfigurationImportSelector.class),借助EnableAutoConfigurationImportSelector,@EnableAutoConfiguration 可以帮助 SpringBoot 应用将所有符合条件的@Configuration 配置都加载到当前 SpringBoot 使用的 IoC 容器。 @ComponentScan

    @ComponentScan 这个注解在 Spring 中很重要,它对应 XML 配置中的元素, @ComponentScan 的功能其实就是自动扫描并加载符合条件的组件(比如@Component 和 @Repository 等)或者 bean 定义,最终将这些 bean 定义加载到 IoC 容器中。

    SpringCloud

    SpringCloud 简介

    spring Cloud 是一个基于 Spring Boot 实现的云应用开发工具,它为基于 JVM 的云应用开发中的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简单的开发方式。

    SpringCloud 核心组件

    服务注册发现 - Netflix Eureka

    配置中心 - spring cloud config

    负载均衡-Netflix Ribbon

    断路器 - Netflix Hystrix

    路由(网关) - Netflix Zuul

    微服务

    微服务是一种可以让软件职责单一、松耦合、自包含、可以独立运行和部署的架构思想。关键思想就是:拆分、单一、独立、组件化。把原本一个庞大、复杂的项目按业务边界拆分一个一个独立运行的小项目,通过接口的方式组装成一个大的项目。

    Docker

    Docker 简介

    Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。 Docker 的基础是 Linux 容器(LXC)等技术。在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单。

    Docker 理解

    Docker 其实和虚拟机的目的差不多,都是虚拟化技术,但是 docker 比虚拟机更加轻量级,更快,更加易于移植。

    镜像: 创建虚拟机和 docker 都必不可少的东西。创建一个虚拟机,就先得下载操作系统的 ISO 镜像文件,然后通过镜像文件安装操作系统,和实体机类似,然后能在虚拟机中去安装各种软件。

    容器: 通俗拿 VM 虚拟机和 Docker 来举例,一个容器就类似于一个虚拟机,只不过在 Docker 技术的术语上称为容器。这个容器里装的就是我们部署的应用在运行,和虚拟机一样可以开机,关机,重启。Docker 称为容器的运行,关闭,重启。而且这个容器可以打包为镜像文件,类似虚拟机快照的文件,放在其它虚拟机上又可以保持原样能运行,Docker 也是如此,把容器打包为镜像文件,然后在新的服务器安装好的 Docker 环境下导入进去,保持原来的状态能够运行。

    Redis

    Redis 简介

    Remote Dictionary Server(Redis)是一个基于 key-value 键值对的持久化数据库存储系统。支持多种数据结构,这些数据类型都支持 push/pop、add/remove 及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。

    Redis 支持的数据类型

    字符串(strings)
    散列(hashes)
    列表(lists)
    集合(sets)
    有序集合(sorted sets)

    Redis 应用场景

    缓存
    计数器
    发布订阅构建消息系统
    排行榜

    Redis 持久化

    RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。 AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。 AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。 Redis 还可以在后台对 AOF 文件进行重写(rewrite),使得 AOF 文件的体积不会超出保存数据集状态所需的实际大小。

    Redis 的优势

    性能极高 – Redis 能读的速度是 110000 次/s,写的速度是 81000 次/s 。

    丰富的数据类型 – Redis 支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
    原子 – Redis 的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过 MULTI 和 EXEC 指令包起来。丰富的特性 – Redis 还支持 publish/subscribe, 通知, key 过期等等特性。

    Solr

    Solr 简介

    Solr 是一个基于 Lucene 的 Java 搜索引擎服务器。Solr 提供了层面搜索、命中醒目显示并且支持多种输出格式(包括 XML/XSLT 和 JSON 格式)。它易于安装和配置,而且附带了一个基于 HTTP 的管理界面。Solr 已经在众多大型的网站中使用,较为成熟和稳定。Solr 包装并扩展了 Lucene,所以 Solr 的基本上沿用了 Lucene 的相关术语。更重要的是,Solr 创建的索引与 Lucene 搜索引擎库完全兼容。通过对 Solr 进行适当的配置,某些情况下可能需要进行编码,Solr 可以阅读和使用构建到其他 Lucene 应用程序中的索引。此外,很多 Lucene 工具(如 Nutch、 Luke)也可以使用 Solr 创建的索引。

    Solr 配置

    Schema.xml:

    在下载 solr 包的安装解压目录的\solr\example\solr\collection1\conf 中找到,它就是 solr 模式关联的文件。

    fieldtype 节点主要用来定义数据类型;

    field 节点指定建立索引和查询数据的字段;

    solrQueryParser 指定搜索时多个词之间的关系,可以是 or 或 and。

    solrconfig.xml:

    配置文件主要定义了 SOLR 的一些处理规则,包括索引数据的存放位置,更新,删除,查询的一些规则配置。

    datadir 节点定义了索引数据和日志文件的存放位置; lib 节点表示 solr 引用包的位置。

    倒排索引

    正排表(索引)是以文档的 ID 为关键字,表中记录文档中每个字的位置信息,查找时扫描表中每个文档中字的信息直到找出所有包含查询关键字的文档。
    在这里插入图片描述
    倒排表(索引)以字或词为关键字进行索引,表中关键字所对应的记录表项记录了出现这个字或词的所有文档,一个表项就是一个字表段,它记录该文档的 ID 和字符在该文档中出现的位置情况。在这里插入图片描述

    RabbitMQ/ActiveMQ

    RabbitMQ 简介

    RabbitMQ 是一个由 Erlang 语言开发的 AMQP 的开源实现。

    AMQP:Advanced Message Queue,高级消息队列协议。它是应用层协议的一个开放标准,为面向消息的中间件设计,基于此协议的客户端与消息中间件可传递消息,并不受产品、开发语言等条件的限制。

    RabbitMQ 特点

    可靠性(Reliability): 使用持久化、传输确认和发布确认机制来保证可靠性。

    灵活的路由(Flexible Routing):在消息进入队列之前,通过 Exchange 来路由消息的。对于典型的路由功能,RabbitMQ 已经提供了一些内置的 Exchange 来实现。针对更复杂的路由功能,可以将多个 Exchange 绑定在一起,也通过插件机制实现自己的 Exchange 。

    高可用(Highly Available Queues):队列可以在集群中的机器上进行镜像,使得在部分节点出问题的情况下队列仍然可用。

    多种协议(Multi-protocol):RabbitMQ 支持多种消息队列协议,比如 STOMP、MQTT 等。多语言客户端(Many Clients):RabbitMQ 几乎支持所有常用语言,比如 Java、.NET、Ruby等。

    管理界面(Management UI):RabbitMQ 提供了一个易用的用户界面,使得用户可以监控和管理消息 Broker 的许多方面。

    跟踪机制(Tracing):如果消息异常,RabbitMQ 提供了消息跟踪机制,使用者可以找出发生了什么。

    插件机制(Plugin System):RabbitMQ 提供了许多插件,来从多方面进行扩展,也可以编写自己的插件。

    RabbitMQ 工作模式

    简单模式:一个生产者发送消息到队列,一个消费者接收。

    工作队列模式:一个生产者,多个消费者,每个消费者获取到的消息唯一,多个消费者只有一个队列。

    发布/订阅模式:一个生产者发送的消息会被多个消费者获取,每个消费者只能从自己订阅的队列中获取。

    路由模式:生产者发布消息的时候添加路由键,消费者绑定队列到交换机时添加键值,这样就可以接收到需要接收的消息。

    通配符模式:基本思想和路由模式是一样的,只不过路由键支持模糊匹配,符号“#”匹配一个或多个词,符号“*”只匹配一个词。

    ActiveMQ 简介

    ActiveMQ 是 Apache 推出的一款开源的,完全支持 JMS1.1 和 J2EE1.4 规范的 JMS Provider 实现的消息中间件。

    ActiveMQ 工作模式

    点对点模式:一个消息只有一个消费者消费。

    发布/订阅模式:订阅一个主题的消费者只能消费自它订阅之后发布的消息。JMS 规范允许客户创建持久订阅,这在一定程度上放松了时间上的相关性要求。持久订阅允许消费者消费它在未处于激活状态时发送的消息。

    MQ 对比

    在这里插入图片描述

    Dubbo

    Dubbo 简介

    Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,以及 SOA 服务治理方案。

    其核心部分包括:

    远程通讯:提供对多种基于长连接的 NIO 框架抽象封装,包括多种线程模型、序列化、"请求-响应"模式的信息交换方案;

    集群容错:提供基于借口方法的透明远程过程调用,包括多协议支持、软负载均衡、失败容错、地址路由、动态配置等集群支持;

    自动发现:基于注册中心目录服务,使服务消费方能动态地查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。

    Dubbo 开发流程

    第一步:要在系统中使用 dubbo 应该先搭建一个注册中心,一般推荐使用 zookeeper;第二步:有了注册中心然后是发布服务,发布服务需要使用 spring 容器和 dubbo 标签来发布服务。并且发布服务时需要指定注册中心的位置;

    第三步:服务发布之后就是调用服务。一般调用服务也是使用 spring 容器和 dubbo 标签来引用服务,这样就可以在客户端的容器中生成一个服务的代理对象,在 action 或者 Controller 中直接调用 service 的方法即可。

    Zookeeper 注册中心的作用主要就是注册和发现服务的作用。类似于房产中介的作用,在系统中并不参与服务的调用及数据的传输。

    FastDFS

    FastDFS 简介

    FastDFS 是一个开源的高性能分布式文件系统(DFS)。 它的主要功能包括:文件存储,文件同步和文件访问,以及高容量和负载平衡。主要解决了海量数据存储问题,特别适合以中小文件(建议范围:4KB < file_size <500MB)为载体的在线服务。

    FastDFS 系统有三个角色:跟踪服务器(Tracker Server)、存储服务器(Storage Server)和客户端(Client)。

    Tracker Server:跟踪服务器,主要做调度工作,起到均衡的作用;负责管理所有的 storage server 和 group,每个 storage 在启动后会连接 Tracker,告知自己所属 group 等信息,并保持周期性心跳。

    Storage Server:存储服务器,主要提供容量和备份服务;以 group 为单位,每个 group 内

    可以有多台 storage server,数据互为备份。

    Client:客户端,上传下载数据的服务器,也就是我们自己的项目所部署在的服务器。
    在这里插入图片描述

    Nginx

    Nginx 简介

    Nginx 是一款高性能的 http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。由俄罗斯的程序设计师 Igor Sysoev 所开发,官方测试 nginx 能够支支撑 5 万并发链接,并且 cpu、内存等资源消耗却非常低,运行非常稳定。

    Nginx 功能

    静态 HTTP 服务器:Nginx 是一个 HTTP 服务器,可以将服务器上的静态文件(如 HTML、图片)通过 HTTP 协议展现给客户端。

    反向代理服务器:客户端本来可以直接通过 HTTP 协议访问某网站应用服务器,但如果单台服务器承受不住压力需要使用多台服务器共同处理请求,这时可以在中间加上一个 Nginx,客户端请求 Nginx,Nginx 请求应用服务器,然后将结果返回给客户端,此时 Nginx 就是反向代理服务器。

    负载均衡:当客户端访问量很大,通过反向代理的方式,使用轮询、加权轮询和 IP Hash 的策略将请求分配给多台服务器。

    Quartz

    Quartz 简介

    Quartz 是一个任务调度框架。它具有以下特点:

    强大的调度功能,例如支持丰富多样的调度方法,可以满足各种常规及特殊需求;

    灵活的应用方式,例如支持任务和调度的多种组合方式,支持调度数据的多种存储方式;分布式和集群能力,Terracotta 收购后在原来功能基础上作了进一步提升;

    作为 Spring 默认的调度框架,Quartz 很容易与 Spring 集成实现灵活可配置的调度功能。

    Quartz 核心元素

    Scheduler:任务调度器,实际执行任务调度的控制器。在 spring 中通过 SchedulerFactoryBean 封装起来;

    Trigger :触发器,用于定义任务调度的时间规则,有 SimpleTrigger 、 CronTrigger 、

    DateIntervalTrigger 和 NthIncludedDayTrigger,其中 CronTrigger 用的比较多,在 spring 中

    封装在 CronTriggerFactoryBean 中;

    Calendar:一些日历特定时间点的集合。一个 trigger 可以包含多个 Calendar,以便排除或

    包含某些时间点;

    JobDetail:用来描述 Job 实现类及其它相关的静态信息。如 Job 名字、关联监听器等信息。在 spring 中有 JobDetailFactoryBean 和 MethodInvokingJobDetailFactoryBean 两种实现,如果任务调度只需要执行某个类的某个方法,可以通过 MethodInvokingJobDetailFactoryBean 来调用;

    Job:是一个接口,只有一个方法 void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext 类提供了调度上下文的各种信息。Job 运行时的信息保存在 JobDataMap 实例中。实现 Job 接口的任务,默认是无状态的,若要将 Job 设置成有状态的,在 quartz 中是给实现的 Job 添加@DisallowConcurrentExecution 注解,在与 spring 结合中可以在 spring 配置文件的 job detail 中配置 concurrent 参数。


    数据库笔试题

    用一条 SQL 语句查询出每门课都大于 80 分的学生姓名

    在这里插入图片描述

    # 准备数据的 sql 代码:
    
    create	table	score(id	int	primary	key	auto_increment,namevarchar(20),subject
    
    varchar(20),score int);
    
    insert into score values
    
    (null,'张三','语文',81),
    
    (null,'张三','数学',75),
    
    (null,'李四','语文',76),
    
    (null,'李四','数学',90),
    
    (null,'王五','语文',81),
    
    (null,'王五','数学',100),
    
    (null,'王五 ','英语',90);
    
    #答案:
    
    #A:select distinct name from score where name not in (select distinct name from score where score<=80)
    
    #B:select distinct name t1 from score where 80< all (select score from score where name=t1)
    
    所有球队之间的比赛组合

    一张叫 team 的表,里面只有一个字段 name,一共有 4 条纪录,分别是 a、b、c、d,对应四个球队,现在四个球队进行比赛,用一条 sql 语句显示所有可能的比赛组合。

    #答案:select a.name,b.name	from team a, team b where a.name < b.name
    
    显示文章标题,发帖人、最后回复时间

    表:id,title,postuser,postdate,parentid

    准备 sql 语句:

    drop table if exists articles;
    create table articles(id int auto_increment primary key,titlevarchar(50), postuser varchar(10), postdate datetime,parentid int referencesarticles(id)); insert into articles values
    
    (null,'第一条','张三','1998-10-10 12:32:32',null), (null,'第二条','张三','1998-10-10 12:34:32',null), (null,'第一条回复 1','李四','1998-10-10 12:35:32',1), (null,'第二条回复 1','李四','1998-10-10 12:36:32',2), (null,'第一条回复 2','王五','1998-10-10 12:37:32',1), (null,'第一条回复 3','李四','1998-10-10 12:38:32',1), (null,'第二条回复 2','李四','1998-10-10 12:39:32',2), (null,'第一条回复 4','王五','1998-10-10 12:39:40',1);
    
    #答案:
    
    select a.title,a.postuser, (select max(postdate) from articles where parentid=a.id ) reply from articles a where a.parentid is null;
    
    #注释:子查询可以用在选择列中,也可用于 where 的比较条件中,还可以用于 from 从句中。
    
    

    航空网的几个航班查询题

    在这里插入图片描述

    1、查询起飞城市是北京的所有航班,按到达城市的名字排序

    参与运算的列是我起码能够显示出来的那些列,但最终我不一定把它们显示出来。各个表组合出来的中间结果字段中必须包含所有运算的字段。

    select * from flight f,city c
    
    where f.endcityid =c.cityid and startcityid =
    
    (select c1.cityidfrom city c1 where c1.cityname = "北京")
    
    order by c.citynameasc;
    
    select flight.flightid,'北京' startcity, e.cityname from flight,city e
    
    where flight.endcityid=e.cityid and flight.startcityid=( selectcityid from city where cityname='北京');
    
    select flight.flightid,s.cityname,e.cityname from flight,city s,city e 
    
    where flight.startcityid=s.cityid and s.cityname='北京' andflight.endCityId=e.cit yID order by e.cityName desc;
    
    
    2、查询北京到上海的所有航班纪录(起飞城市,到达城市,起飞时间,航班号)
    select c1.CityName,c2.CityName,f.StartTime,f.flightID
    
    from city c1,city c2,flight f
    
    where f.StartCityID=c1.cityID
    
    and f.endCityID=c2.cityID
    
    and c1.cityName='北京'
    
    and c2.cityName='上海'
    
    3、查询具体某一天(2005-5-8)的北京到上海的的航班次数
    select count(*) from
    
    (select c1.CityName,c2.CityName,f.StartTime,f.flightID
    
    from city c1,city c2,flight f
    
    where f.StartCityID=c1.cityID
    
    and f.endCityID=c2.cityID
    
    and c1.cityName='北京'
    
    and c2.cityName='上海'
    
    and 查帮助获得的某个日期处理函数(startTime) like '2005-5-8%' mysql 中提取日期部分进行比较的示例代码如下:
    
    select * from flight wheredate_format(starttime,'%Y-%m-%d')='1998-01-02'
    

    ok,Java面试宝典就总结到这里
    一定会及时更新最新Java面试题
    要是对我的文章感兴趣的话,就快关注我吧

    下一篇:Java面试总结

    给我们一个微信勾搭的机会

    在这里插入图片描述

    展开全文
  • 斩获 offer 的 Java 面试宝典

    万次阅读 多人点赞 2021-04-11 11:40:29
    这是本人整理的数万字的面试笔记,基本上涵盖了 Java 领域的所有技术栈,本人也是凭借这份面试笔记斩获了近 10 个 offer,面试成功率高达80%。当然这份笔记是我根据自身的经验和技术栈整理的,自己觉得很重要的或者...

    文章目录

    这是本人整理的数万字的面试笔记,基本上涵盖了 Java 领域的所有技术栈,本人也是凭借这份面试笔记斩获了近 10 个 offer,面试成功率高达80%。当然这份笔记是我根据自身的经验和技术栈整理的,自己觉得很重要的或者记不清的就会记录记录下来,面试被问到的时候也有回答的思路。现在共享给大家,希望对准备面试的小伙伴有帮助。

    1. 微服务

    1.1 主流注册中心对比

    zookeeper:zookeeper 作为注册中心主要是因为它具有节点变更通知功能。只要客户端监听相关服务节点,服务节点有所变更就能及时的通知到监听客户端,非常方便。zookpeeper 是cp模式的。

    eureka:是 netflix 开源的 基于RestFulAPI 风格开发的服务注册和发现组件。现在不会再更新。

    consul:是使用go 语言开发的支持多数据中心分布式高可用的服务发布和注册的服务软件。

    nacos:是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

    1.2 eureka 心跳检测和自我保护机制

    心跳检测:eureka 每隔30 秒就会向注册中心续约心跳一次,也就是报活。如果没有续约,租约在90s 后到期,然后服务就会失效,每隔30s的续约操作,就是心跳检测。

    自我保护:eureka 服务端如果在15 分钟内,超过 85% 的客户端节点都没有正常心跳,那么Eureka 就认为客户端和注册中心出现了网络故障。而微服务本身是可正常运行的,此时不应该移除这个微服务,所以引入了自我保护机制。在自我保护状态下,不会移除任何服务,能接受新服务的注册和查询请求,但是不会和集群中其他节点同步。

    1.3 Ribbon 负载均衡策略

    1、轮寻策略

    2、随机策略

    3、重试策略:一定时间内循环重试。继承随机策略。

    4、最小连接数策略:遍历serverList,选出可用且连接数最小的server.

    5、可用过滤策略:扩展了轮寻策略,会先通过默认的轮询选取一个 server,再判断 server 是否超时可用。

    6、区域权衡策略:扩展了轮询策略。除了过滤连接超时和连接数过多的server,还会过滤掉不符合要求的 zone 区域里面所有的节点。然后在剩下的节点中轮询获取。

    1.4 Hystrix 舱壁模式

    使用舱壁避免了单个工作负载(或服务)消耗掉所有资源,从而导致其他服务出现故障的场景。这种模式主要是通过防止由一个服务引起的级联故障来增加系统的弹性。通过应用舱壁模式,可以保护有限的资源不被耗尽。为了避免问题服务请求过多导致正常服务⽆法访问,Hystrix 不是采⽤增加线程数,⽽是单独的为每⼀个控制⽅法创建⼀个线程池的⽅式,这种模式叫做“舱壁模式"。

    1.5 Hystrix 工作模式

    1、当调⽤出现问题时,开启⼀个时间窗(10s)

    2、在这个时间窗内,统计调⽤次数是否达到最⼩请求数?

    • 如果没有达到,则重置统计信息,回到第1步;
    • 如果达到了,则统计失败的请求数占所有请求数的百分⽐,是否达到阈值?
      • 如果达到,则跳闸(不再请求对应服务)
      • 如果没有达到,则重置统计信息,回到第1步

    3、如果跳闸,则会开启⼀个活动窗⼝(默认5s),每隔5s,Hystrix 会让⼀个请求通过,到达那个问题服务,看是否调⽤成功,如果成功,重置断路器回到第1步,如果失败,回到第3步。

    1.6 Fein

    fegin 是NetFlix 开发的一个轻量级 RestFulf 的 HTTP 服务客户端。用来进行远程调用。

    1.7 gateway

    gateway 核心逻辑就是路由转发加执行过滤器链。

    客户端向gateway 发送请求。然后在gateway handler Mapping 中找到与请求相匹配的路由,然后handler 通过制定了过滤器链来将请求发送到我们实际服务执行业务逻辑,然后返回。在过滤器中可以进行参数加解密,参数校验、权限校验、日志输出、协议转换等等。

    2. 并发编程

    2.1 多线程

    2.1.1 创建一个阻塞队列

    核心思想就是当队列为空时,调用出队列的方法,会进行wait() 等待。直到有数据入队列时,调用notify() 方法。同样的在队列满是,入队列会阻塞,直到有出队列才唤醒。

    public class MyBlockingQueue {
    
        private int[] data=new int[10];
        private int putIndex;
        private int getIndex;
        private int size;
    
        public synchronized void put(int val){
            if(size==data.length){
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                put(val);
            }else {
                data[putIndex]=val;
                putIndex++;
                if(putIndex==data.length){
                    putIndex=0;
                }
                size++;
            }
        }
    
        public synchronized int get(){
            if(size==0){
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return get();
            }else {
                int val = data[getIndex];
                getIndex++;
                if(getIndex==data.length){
                    getIndex=0;
                }
                size--;
                return val;
            }
        }
    
    }
    
    2.1.2 为什么wait() 方法要释放锁。

    因为当一个线程进入一个 synchronized 修饰的同步方法后,会锁住当前对象,调用 wait() 方法进入阻塞状态。如果不释放当前对象的锁的话,其他线程永远获取不到当前对象的锁,也就没有办法唤醒当前线程了,这样就形成了死锁。所以在调用wait() 方法会释放锁,等待其他线程获取当前对象锁,调用notify() 唤醒此线程。然后此线程重新获得锁,执行剩下的操作,执行结束后,会再次的释放锁。

    2.1.3 volatile 关键字的作用

    1、保证64位写入的原子性。

    2、内存可见性

    3、禁止指令重新排序。

    2.1.4 synchronized

    synchronized 实现原理是获取不到锁先自旋,自旋依然获取不到锁,再阻塞。

    2.2 JUC

    2.2.1 阻塞队列

    阻塞队列有基于数组实现的ArrayBlockQueue 和基于 链表实现的 LinkBlockQueue。以及还有优先级的 PriorityBlockQuere,按照元素的优先级出队列,实现了Comparable 接口。以及延时队列。根据延时时间大小出队列的,实际上是未来时间减去当前时间放入,DelayQueue 中的元素。如果getDelay() 小于等于0,说明该元素到期,可以出队列了。同步队列没有容量,先调用put(),线程就会阻塞,只要等另一个线程调用了task(),两个线程才会唤醒。

    2.2.2 CopyOnWrite

    是指在写的时候,不会直接操作源数据,而是先copy 一份数据进行修改,然后通过悲观锁或者乐观锁的方式写回。这样的好处是,读不用加锁。

    CopyOnwriteArrayList 读操作的时候不会加锁,只有写的时候才会加同步锁,所以是线程安全的 ArrayList。

    CopyOnwriteArraySet 就是用array 实现的一个线程安全的 Set .保证所有元素不重复,封装的是CopyOnwriteArrayList 。利用CopyOnwriteArrayList 的addAllAbsent() 方法。

    2.2.3 锁

    为了实现一把具有阻塞或唤醒功能的锁,需要几个核心要素:

    1. 需要一个state变量,标记该锁的状态。state变量至少有两个值:0、1。对state变量的操作,使用CAS保证线程安全。

    2. 需要记录当前是哪个线程持有锁。

    3. 需要底层支持对一个线程进行阻塞唤醒操作。

    4. 需要有一个队列维护所有阻塞的线程。这个队列也必须是线程安全的无锁队列,也需要使用CAS。

    2.2.4 AQS

    AbstractQueuedSynchronizer 的核心就是一个双向链表形成的阻塞队列以及CAS.

    2.2.5 CAS

    CAS 名为:compare and swap。是比较内存中的值是否和预期值一致,如果一致就进行更新。这个过程是原子的。cas 有三个操作数,内存值,预期值和新值。只有当内存值和预期值相等时,才会将内存值更新为新值。否则什么都不做。底层是通过unsafe 类保证原子性的,unsafe类中都是native 方法,可以直接操作内存。

    缺点:存在ABA 问题。解决方案就是加版本号,或者加时间戳。

    2.2.5 ReentrantLock 互斥锁

    Condition 本身也是一个接口,其功能和wait/notify类似,Condition 也必须和Lock一起使用。因此,在Lock的接口中,有一个与Condition相关的接口。

    await() 是获取锁线程阻塞方法。signal() 是唤醒线程的方法。

    2.3 线程池

    线程池是一个典型的生产者消费者模型。线程池的核心是使用阻塞队列。我们常用的就是 ThreadPoolExecutor。

    2.3.1 ThreadPoolExecutor

    ThreadPoolExecutor 主要是 包含一个阻塞队列和一组线程集合 Workers。每个线程是一个worker 对象,worker 继承了AQS 。

    ThreadPoolExecutor 包含7 个参数。

    corePoolSize:在线程池中始终维护的线程个数。核心线程数

    maxPoolSize:在corePooSize已满、队列也满的情况下,扩充线程至此值。最大线程数

    keepAliveTime/TimeUnit:maxPoolSize 中的空闲线程,销毁所需要的时间,总线程数收缩回corePoolSize。存活时间和单位

    blockingQueue:线程池所用的队列类型。阻塞队列

    threadFactory:线程创建工厂

    RejectedExecutionHandler:corePoolSize已满,队列已满,maxPoolSize 已满,最后的拒绝策略。

    提交过程的核心流程:

    1、先判读当前线程数是否小于 corePoolSize 。如果小于就新建线程执行

    2、如果大于,就判断阻塞队列是否已经满了,如果没有满,就加入阻塞队列中。

    3、如果满了,就判断当前线程数是否小于 maxPoolSize 。如果小于,就直接创建线程执行。如果大于就根据拒绝策略,拒绝任务。

    线程池的关闭:

    在调用shutdown() 或者shutdownNow() 之后,线程池并不会立即关闭,会等待所有任务执行完成之后,才会关闭线程池。

    shutdown() 不会清空任务队列,并且只会中断空闲线程。

    shutdownNow() 会清空任务队列,并且中断所有的线程。

    2.3.2 线程池拒绝策略

    线程池有四种拒绝策略

    1、丢弃任务,并抛出异常

    2、丢弃任务,单不抛出异常

    3、丢弃队列最前面的任务,然后重新提交当前任务。

    4、线程池什么都不做,由当前线程自己处理。

    2.3.3 ScheduledThreadPoolExecutor

    ScheduledThreadPoolExecutor实现了按时间调度来执行任务。有延迟任务和周期性任务。底层实现一个延迟队列来实现的。

    3. java 基础

    3.1 spring 启动的流程(12步)

    1、prepareRefresh()。刷新前预处理。主要是设置启动时间,以及初始化配置文件中的占位符,以及校验配置信息是否正确。

    2、obtainFreshBeanFactory()。获取 Beanfactory。

    3、prepareBeanFactory(beanFactory)。Beanfactory 的准备工作,对BeanFactory 的一些属性进行配置。比如 context 的类加载器

    4、postProcessBeanFactory()。BeanFactory 准备工作完成后,进行的后置处理工作。是一个钩子函数。

    5、invokeBeanFactoryPostProcessors(beanFactory)。实例化并调⽤实现了BeanFactoryPostProcessor接⼝的Bean

    6、registerBeanPostProcessors(beanFactory)。注册BeanPostProcessor(Bean的后置处理器),在创建Bean的前后执行

    7、initMessageSource()。初始化 MessageSource 组件,并将信息加入allpication.singletonObjects 中。

    8、initApplicationEventMulticaster()。初始化事件派发器,并加入到singletonObjects 中

    9、onRefresh()。子类重写这个方法,在容器刷新时可以自定义逻辑。

    10、registerListeners()。注册应用监听器。 就是 注册 ApplicationListener 接口监听器 bean

    11、finishBeanFactoryInitialization()。初始化所有没有设置延时加载的Bean

    12、finishRefresh()。完成context 的刷新,发布事件。

    3.2 BeanFactory 创建流程

    1、判断是否已经存在BeanFactory,如果存在,就销毁Bean 和BeanFactory。

    2、创建 BeanFactory

    3、为当前BeanFactory 设置序列化id

    4、将bean 对象加载到 BeanFactory 对象的 beanDefinitionMap 中。

    5、返回 BeanFactory

    3.3 Bean 创建流程

    1、初始化所有剩下的⾮懒加载的单例bean

    2、初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性)

    3、填充属性

    4、初始化⽅法调⽤(⽐如调⽤afterPropertiesSet⽅法、init-method⽅法)

    5、调⽤BeanPostProcessor(后置处理器)对实例bean进⾏后置处

    3.4 Bean 生命周期(11步)

    在这里插入图片描述

    1、根据配置情况调用 Bean的构造方法或者工厂方法实例化Bean

    2、利用依赖注入完成Bean的所以属性值的配置注入

    3、如果Bean 实现了BeanNameAware 接口,则spring 调用Bean的setBeanName() 传入当前Bean的id

    4、如果Bean实现了BeanFactoryAware 接口,调用setBeanFactory() 方法传入当前工厂实例的引用

    5、如果Bean 实现了ApplicationContextAware 接口,通过调用setApplicationContext 传入当前applicationContext 实例的引用。

    6、如果BeanPostProcessor 和Bean 关联,则Spring 将调用改接口的预初始化方法。postProcessBeforeInitialization() 是前置处理的方法,Spring的AOP就是利用它实现的。

    7、如果Bean 实现了InitializingBean 接口,需要实现afterPropertiesSet 方法

    8、如果在配置文件中通过init-method 属性指定了初始化方法。则的调用该方法。

    9、如果BeanPostProcessor 和Bean 关联,则Spring 将调用该接口的初始化方法postProcessAfterInitialization().此时Bean可以被应用系统使用。

    10、如果在Bean标签中指定了Bean的作用范围的scope=“singleton” 则将改Bean 方法singletonObjects的缓存池中

    11、如果Bean 实现了DisposableBean 接口,则spring会调用destory() 方法 将Spring中的Bean销毁。

    3.5 Autowired 和Resource 注解的区别

    1、autowired 是spring 提供的注解,@Resource是javaee 提供的注解。

    2、Autowired 采用的是按类型注入。当一个类有多个Bean的时候需要配合@Qualifier 来指定唯一的Bean。而@Resource 默认安装byName 自动注入。

    3、@Resource 可以执行 name 和type .可以通过type 注入,也可以通过name 来注入。

    3.6 循环依赖

    利用三级缓存来解决循环依赖的。

    1、当创建对象A的Bean 的时候,会先将A对象Bean 放入三级缓存,然后填充属性;

    2、发现依赖对象B ,但是对象B 还没有创建,所以就创建对象B

    3、对象B在创建过程中,发现依赖对象A,就先从一级缓存中获取,没有获取到就从二级缓存中找,没有找到就从三级缓存中找,找到了还没有创建完成的对象A .然后将对象A 进行一些处理移入二级缓存中。

    4、这样对象B就可以继续完成Bean 创建的其他步骤知道完全创建好。

    5、B 对象的Bean 创建好之后,放入了一级缓存SingLetonObject中,对象A可以继续完成创建。最终创建好的A对象也会进入一级缓存中。

    3.7 事务的传播行为(7中类型)

    事务往往在service 层控制,如果在 service 层方法A调用另个 service 的方法 B 。A和B 本身都本身都添加了事务控制,那么在A调用B 的时候就需要进行事务的一些协商,这就是事务的传播行为。

    有如下7中类型:

    A调用B,站在B的角度来定义传播行为。

    1、如果当前没有事务,就新建事务;如果存在一个事物,就加入到当前事务中。这是最常见的一种类型。

    2、支持当前事务,如果没有事务,就以非事务执行。

    3、支持当前事务,如果没有事务,就抛出异常。

    4、新建事务,如果当前存在事务,就将当前事务挂起。

    5、以非事务运行,如果存在当前事务,就将当前事务挂起。

    6、以非事务运行,如果存在当前事务,就抛出异常。

    7、如果当前存在事务,就在嵌套事务内执行。如果当前没有事务,就创建一个事物执行。

    3.8 spring mvc 请求处理流程(10步)

    1、DispatcherServlet 接收到客户端发送的请求。

    2、DispatcherServlet 收到请求调用HandlerMapping 处理器映射器。

    3、HandleMapping 根据请求URL 找到对应的handler 以及处理器 拦截器,返回给DispatcherServlet

    4、DispatcherServlet 根据handler 调用HanderAdapter 处理器适配器。

    5、HandlerAdapter 根据handler 执行处理器,也就是我们controller层写的业务逻辑,并返回一个ModeAndView

    6、HandlerAdapter 返回ModeAndView 给DispatcherServlet

    7、DispatcherServlet 调用 ViewResolver 视图解析器来 来解析ModeAndView

    8、ViewResolve 解析ModeAndView 并返回真正的view 给DispatcherServlet

    9、DispatcherServlet 将得到的视图进行渲染,填充到request域中

    10、返回给客户端响应结果。

    在这里插入图片描述

    3.9 过滤器拦截器

    • 过滤器(Filter):对Request请求起到过滤的作⽤,作⽤在Servlet之前,如果配置为/*可以对所有的资源访问(servlet、js/css静态资源等)进⾏过滤处理

    • 拦截器(Interceptor):是SpringMVC、Struts 等表现层框架⾃⼰的,不会拦截 jsp/html/css/image 的访问等,只会拦截访问的控制器⽅法(Handler)。拦截器会作用三个地方:在 handler 执行之前执行一次,用来校验参数合理性,handler 之后、视图解析器之前执行一次,视图解析之后执行一次。

    image-20200609153128257

    3.10 springboot 启动流程(9步)

    1、加载并启动监听器

    2、创建项目运行环境,并加载配置

    3、创建 spring 容器。

    4、运行spring 容器的前置处理。主要是容器刷新之前的准备工作,设置容器环境,并且将启动类注入容器,为后面开启自动化配置服务。

    5、刷新是spring 容器。通过refresh() 方法对整个IOC 容器初始化。包含bean 资源点定位解析注册等。

    6、运行spring 容器后置处理器。扩展接口,如果有自定义需求,可以重写该方法。

    7、发布结束执行的事件。

    8、执行自定义执行器。

    9、返回容器。

    3.11. 说说 hashMap 的原理

    在jdk 1.7 版本,hashmap 的数据结构是 数组加链表

    在jdk 1.8 版本,hashmap 的数据结构是数组加链表叫红黑树。当数组长度大于64 且链表长度大于8时,链表就会转换成红黑树。

    3.12. synchronized 和 ReentrantLock 的区别

    1、synchronized 是 JVM 隐式实现的,而 ReentrantLock 是 Java 语言提供的 API;

    2、ReentrantLock 可设置为公平锁,而 synchronized 却不行;

    3、ReentrantLock 只能修饰代码块,而 synchronized 可以用于修饰方法、修饰代码块等;

    4、ReentrantLock 需要手动加锁和释放锁,如果忘记释放锁,则会造成资源被永久占用,而 synchronized 无需手动释放锁;

    5、ReentrantLock 可以知道是否成功获得了锁,而 synchronized 却不行。

    4. jvm

    4.1 jvm 内存模型

    jvm 内存分为:程序计数器、虚拟机栈、本地方法栈、堆、方法区。

    程序计数器:线程私有。是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器。

    虚拟机栈:线程私有。用于存储栈帧。每个方法在执行时都会创建一个栈帧(Stack Frame)**,**用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直到执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

    本地方法栈:线程私有。用于 虚拟机 Native 方法

    堆:线程共享、保存对象实例,所有的对象实例都在堆上存储。

    方法区:线程共享。存储被虚拟机加载的类信息、常量、静态变量等。

    4.2 jvm 堆

    4.2.1 堆内存分布

    jvm 将堆内存分为 年轻代和年老代。年轻代和年老代的比例为1:2 。年老代用来存储存活时间比较长或者大对象。年轻代用来存储错过时间比较短的对象。年轻代中又分为Eden 区和两个Survivor 区,比例为8:1:1。

    4.2.2 对象分配过程

    1、首先会将对象放入年轻代的 Eden 区,如果Eden 区能发下就放入。

    2、如果 Eden 区放不下了,就会触发 YangGC。会对Eden 区和使用的 Survivor 区进行垃圾回收,存活的对象保存到另一个空闲的Survivor 区。然后将新对象放入 Eden 区。

    3、当Survivor 区有对象经历 15 次 yangGC 后还存活,就迁移到年老代。15次是默认的,可以调整。

    4、如果新增对象大小超过Eden 区 一半时,会直接加入年老区。如果年老区 能放下就放入。

    5、如果年老区放不下,就会触发OldGC。

    6、如果OldGC 后,还是放不下对象,就会触发FullGC

    7、如果FullGC 还放不下,就会报OOM 异常。

    4.3 方法区

    方法区保存的内容:类型信息、域信息、方法信息、运行时常量池。元空间用来存储类的元信息,存储位置为本地内存。静态变量和常量池存储在堆中。

    4.4 类加载的执行过程

    类的生命周期:包含7个阶段,有加载、验证、准备、解析、初始化、使用和卸载。

    image-20210303135001897

    加载:分为预加载和运行时加载、预加载是在JVM启动的时候就加载的class 文件。加载的都是lib/rt.jar 下的 .class 文件。运行时加载是指我们一般的class 文件,只有在用到的时候会先去内存中查一下有没有,没有才会进行加载到内存中。主要获取 .class 文件的二进制流。类信息、静态变量、字节码、常量这些信息会存入 方法区中。

    连接分为验证、准备和解析

    验证:保证 .class 文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全。

    准备:为类的变量分配内存并设置其初始值。这里的初始值是 默认初始值。,比如"public static int value = 123",value在准备阶段过后是0而不是123,给value赋值为123的动作将在初始化阶段才进行;比如"public static final int value = 123;"就不一样了,在准备阶段,虚拟机就会给value赋值为123。

    解析:是虚拟机将常量池内的符号引用替换为直接引用的过程。符号引用是一种定义,可以是任何字面上的含义,而直接引用就是直接指向目标的指针、相对偏移量。

    初始化:类的初始化阶段是类加载的最后一个过程。初始化阶段就是执行类构造器方法的过程。为类变量进行初始化赋值。这里就是我们代码中定义的值了。

    4.5 双亲委派模型

    如果一个类加载器收到类加载的请求,它首先不会自己尝试加载这个类,而是把这个请求委派给自己的父类加载器完成,每个类加载器都是如此,只有当父类加载器在自己范围内找不到指定类时,又会委派自己的子类进行加载。这就是双亲委派模型。这样做的好处是:让类加载尽量都交给父类加载,这样就可以避免不同的子类都需要进行类加载,提升了效率,也更加安全。

    4.6 判断对象已死算法

    1、引用计数算法。当该对象被应用了,计数器就+1,引用失效了,就-1。当计数器值为0 时表示没有被使用,可以回收了。不能解决循环引用的问题。

    2、可达性分析算法。从一系类的 GC root 的对象作为起点,向下搜索到对象的路劲。如果对象没有和 GC root 对象不存在路劲。就会被标记需要清除。

    GC root 对象有哪些?

    1、栈帧中局部变量表的reference 引用所引用的对象。

    2、方法区中 static 静态引用的对象。

    3、方法区中final 常量引用的对象。

    4、所有被同步锁持有的对象。

    5、java 虚拟机内部的引用,如基本数据类型的对象、异常对象、系统类加载器等

    finalize() 方法

    如果对象进行可达性分析,发现对象没有和 GCroot 相连接的引用链,会被第一次标记,随后进行一次筛选,判断是否有必要执行 finalize() 方法。

    如果没有重载finalize() 方法,或者虚拟机已经执行过了该对象的 finalize() 方法,则判定为没有必要,直接等待回收。如果判定有必要执行 finalize() 方法。就会放入F-Queue 队列中,随后由低优先级的线程执行 finalize() 方法。在方法中,可以将当前对象和GCroot 对象建立引用链,摆脱被回收的命运。否则执行完 finalize() 依旧会被回收。

    4.7 引用类型

    java虚拟机有4中引用类型:

    强引用:进行垃圾回收时,垃圾回收器不会对强引用的对象进行回收。

    软引用:只要内存足够,垃圾回收器就就不会回收,只要当内存不足时才会对软引用的对象进行回收。

    弱引用:在垃圾回收器执行垃圾回收时,不管内存够不够,都会对弱引用的对象进行回收。

    虚引用: 它是最弱的一种引用关系。如果一个对象仅持有虚引用,在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收器回收的活动。

    4.8 垃圾回收算法

    4.8.1 分代收集理论

    基于两个假说:

    1、大部分对象都是朝生熄灭的

    2、存活时间越久的对象越难以消亡。

    4.8.2 标记清除算法

    算法分为“标记”和“清除”两个阶段: 首先标记出所有需要回 收的对象, 在标记完成后,统一回收掉所有被标记的对象, 也可以反过来, 标记存活的对象, 统一回收所有未被标记的对象

    在这里插入图片描述

    缺点:内存空间碎片化严重。

    4.8.3 标记复制算法

    当这一块的内存用完了, 就将还存活着 的对象复制到另外一块上面, 然后再把已使用过的内存空间一次清理掉。

    在这里插入图片描述

    缺点:每次有一半的内存空闲,利用率不高。如果99%的对象都是存活的(老年代),那么老年代是无法使用这种算法的。

    4.8.4 标记整理算法

    的“标记-整 理”(Mark-Compact) 算法, 其中的标记过程仍然与“标记-清除”算法一样, 但后续步骤不是直接对可回收对象进行清理, 而是让所有存活的对象都向内存空间一端移动, 然后直接清理掉边界以外的内存 。

    在这里插入图片描述

    4.9 垃圾收集器

    4.9.1 CMS 收集器

    CMS 收集器分为4个步骤:

    1、初始标记: 这个阶段会stop-the-world 。主要是来标记 GC roots 能够直接关联到的对象。标记之后恢复暂停的所有应用。操作速度是比较快的。

    2、并发标记:这个阶段是GC roots 直接关联到的对象开始遍历标记整个对象图的过程,耗时较长,但不用暂停用户线程。可以并发执行。

    3、重新标记:为了修正并发标记阶段用户线程运行导致标记发生变动,从而进行重新标记,也会stop-the-world 。耗时比初始标记会长一点。

    4、并发清理:清理哪些被标记为死亡的对象,并释放内存空间。采用标记清除算法,不用移动存活对象,可以并发执行。

    4.9.2 G1 收集器

    G1 收集器特点:

    1、G1 把堆内存分为多个独立的 region 区域。

    2、G1 沿用了分代思想。保留了年轻代、年老代。但他们不再物理隔离。都通过Region 存储。

    3、G1 采用标记整理算法,局部采用标记复制算法。不会产生内存碎片化。

    4、G1 能充分利用多CPU 、多核硬件环境,尽量缩短STW

    过程:

    初始标记:和CMS 初始标记阶段一样,标记 GC roots 能够直接关联到的对象。会STW

    并发标记:和CMS 并发标记阶段一样。GC roots 直接关联的对象整个对象树进行标记。

    最终标记:修正并发标记阶段,因程序运行产生变化的那部分对象。

    筛选回收:根据时间来进行价值最大化收集。

    4.9.3 ZGC 收集器

    ZGC 是java 11 版本中提供的高效垃圾回收算法,有以下特点:

    1、使用了着色指针技术,利用指针额外信息位,在指针上对对象进行着色标记。

    2、使用了读屏障,使得进行垃圾回收大部分时间都不需要STW,因此大部分时间都是并发处理的。

    3、基于Region ,没有进行分代,也灭有固定Region 的大小,Region 是可以动态创建和销毁的。对大对象可以更好的管理。

    4、压缩整理。在回收后会对 Region 对象进行移动合并,解决碎片化问题。

    过程:

    image-20210304135404162

    1、初始标记:在开始的时候会有短暂的 STW ,用户标记 GC Roots。

    2、并发标记:这个阶段通过对象指针着色来标记,结合读屏障解决单个对象的并发问题。在最后会有一个短暂的STW 来解决边缘情况。

    3、清理阶段:这个阶段会对不再使用的对象进行回收。

    4、并发重定位:就是对存活的对象进行移动,来解决碎片化的问题。也是利用读屏障和用户线程并发处理的。

    5. 设计模式

    5.1 单例模式

    保证一个类仅有一个实例,并提供一个访问它的方法。包含一个静态变量,一个私有的构造方法,一个 public 的静态方法。

    饿汉式、懒汉式、双重校验锁。

    public class SingLeton{
        private volalite static SingLeton sing;
        
        private SingLeton(){
        }
        
        public static SingLeton getSingLeton(){
            if(sing==null){
                synchronized(SingLeton.class){
                    if(sing==null){
                        sing=new SingLeton();
                    }
                }
            }
            return sing;
        }
        
    }
    

    静态内部类。

    public class SingLeton{
        
        private static class SingLetonInner{
            public static final SingLeton sing=new SingLeton();
        }
        private SingLeton(){}
        
        public static SingLeton getInstance(){
            return SingLetonInner.sing;
        }
        
    }
    

    5.2 工厂模式

    工厂模式就是通过工厂来创建想要的对象,而不是自己去创建对象。这样降低了代码间的耦合度。比如一个服饰工厂可以生产衣服,裤子,鞋子,袜子,帽子等等。我们想要用衣服,不用自己来造了,而是和工厂说你想要什么,那工厂就给你生产什么。这就是工厂模式。主要是将创建对象的实例交给工厂类来完成,并进行管理。

    工厂分为简单工厂模式、工厂方法模式和抽象工厂模式。

    简单工厂模式:是工厂模式最简单的一种,实例有工厂直接创建。也就是上面的例子中,你想要衣服,那这个服饰工厂就给你做一件衣服给你。

    工厂方法模式 :就是工厂本身不进行实体对象的创建,而是通过对应的下游工厂来创建然后在返回,有点总工厂子工厂的意思,总工厂管理着所有的子工厂,每个子工厂只生产指定的商品,当通知总部想要什么东西时,总部就通知对应的子工厂生产,拿到产品后再返回客户。

    抽象工厂:就是一个抽象工厂类,里面只是声明可以实现哪些对象,但是具体的实现就交给具体的工厂完成。抽象工厂就好比包皮公司,它告诉你他可生产服饰,也就可以生产食品。那比如你想要衣服,它就给你一个服饰工厂的联系方式,你通过这个服饰工厂来获取到衣服。想要辣条,那他就给你推一个食品公司的联系方式,让这个食品公司给你做。

    工厂方法模式和抽象工厂模式的区别:在于工厂方法模式主要是生产某一类商品。而抽象工厂,我不关心你怎么实现,只要你说你能做这个商品,我就可以为你代言。

    5.3 构建者模式

    将构建一个复杂的对象可以进行拆分成构建一个个简单的对象。然后组装成复杂的对象,就是构建者模式。比如mybatis 中为了构建Configuration 这个复杂对象,就先构建了Dadasource、MapperStment、等很多的对象组成,在解析SqlMapConfig配置文件的时候,就会先将各种配置文件封装到对应的对象中,最后组装成 Configuration 对象

    5.4 代理模式

    代理模式就是我们想要执行的方法通过代理对象来完成,就好比我们要抢票回家,我们不想自己盯着抢,所以就找代理帮我们抢从而达到目的。代理模式分为静态代理和动态代理。

    静态代理:就是具体的代理类,在编译阶段就知道这个代理能做什么事情。就好比抢票的代理一样,它只能做抢票这个代理,而不能代你抢钱哈哈。

    动态代理:动态代理就不同了,它在编译阶段也没有具体的实现。而是在程序运行期间根据JVM的反射机制动态生成的。比较出名的就JDK 动态代理 和cglib 动态代理。

    JDK 动态代理:主要实现InvocationHandle 接口并实现其 invoke 方法。

    Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            Object result = null;
    
                            // 前置增强
                           ....
                            // 调用原有业务逻辑
                            result = method.invoke(obj,args);
                            //后置增强
                            ...
    
                            return result;
                        }
                    })
    

    cglib 动态代理:需要引入其依赖,使用方法和JDK动态代理差不多。实现MethodInterceptor 接口并实现 intercept 方法。

    public Object getCglibProxy(Object obj) {
            return  Enhancer.create(obj.getClass(), new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    Object result = null;
                    //前置增强
                    ...
                    result = method.invoke(obj,objects);
                    //后置增强
                    ...
                    return result;
                }
            });
        }
    

    JDK 动态代理是java 语言自带的功能,提供了稳定的支持。是通过拦截器和反射实现的,jdk 动态代理只能代理继承接口的类。

    cglib 动态代理是第三方提供的工具,基于ASM 实现的,性能比较高,cglib 动态代理无需通过接口实现,它是通过实现子类的方式来完成调用的。

    5.5 适配器模式

    6. 数据结构和算法

    6.1 数据结构

    常见的数据结构如下:

    在这里插入图片描述

    6.1.1 线性表
    6.1.1.1数组

    有限个相同类型的变量组成的集合。物理地址连续(连续的内存空间存储)。

    删除和插入元素的时候,后续的元素需要进行位移。

    扩容数组的时候,需要先创建一个新数据,然后将原数组的值填充到新数组中。

    优点:具有高效的随机访问能力。只需要给出下标,就可以常量时间找到对应元素。

    缺点:插入和删除,会导致其他元素发生位移。影响效率。

    6.1.1.2链表

    链表是物理上不连续的节点组成。每个节点包含两部分。存储数据元素以及指向下个节点的指针。

    常见的链表有:单链表,双链表,循环链表。

    优点:插入,删除、更新的效率高。

    缺点:查询的效率低,不能随机访问。在查询节点的时候,只能从头结点开始一个个的往后找。

    6.1.1.3 栈

    栈是一种线性结构,栈中的元素只能先入后出。最早进入的元素为栈底,最后进入的元素叫栈顶。

    栈可以用数组实现也可以用链表实现。

    6.1.1.4 队列

    队列也是一种线性结构,只能先入先出。队列的出口端叫做队头,队列的入口端加做队尾。

    队列可以用数组实现也可以用链表实现。

    6.1.2 散列表

    散列表也是 hash 表。这种数据结构提供了key 和value 的映射关系。只要给出 key ,就可以高效的查询出它所匹配的 value 。

    6.1.3 树

    树又分为二叉树和多叉树。

    image-20210219105937939

    6.1.3.1 二叉树

    二叉树每个节点最多只有两个子节点。

    6.1.3.2 满二叉树

    一个二叉树所有的非叶子节点都存在左右子节点。且所有的叶子节点都在同一层,就是满二叉树。

    6.1.3.3 完全二叉树

    如果二叉树的深度为k。k-1 层为满二叉树。第k 层,所有节点都连续集中在最左边,则是一颗完全二叉树。

    6.1.3.4 平衡二叉树

    左子树和右子树的深度差的绝对值不超过1。并且左子树和右子树也为平衡二叉树。

    6.1.3.5 二叉查找树

    在二叉树的基础上。如果有左节点,左节点的的值都小于根节点。如果有右节点,右节点的值都大于根节点。二叉查找树又叫二叉排序树。

    6.1.3.6 红黑树

    一种自平衡的二叉查找树。有以下特征:

    1、每个节点不是红色节点就是黑色节点。

    2、根节点是黑色。

    3、每个叶子节点都是黑色的空节点。

    4、如果一个节点是红色的。那么它的子节点必须为黑色。

    5、每个节点到各个叶子节点的包含相同数量的黑节点。

    6、新加入的节点为红色,然后校验是否满足红黑树的规则,。如果不满足则需要进行颜色翻转、左旋、右旋等操作。

    6.1.3.7 B 树

    B 树为一种多叉树。一颗 M 阶的B 树 特征如下:

    1、树的每个节点至多有M 个子节点。

    2、根节点至少有两个子节点。

    3、除根节点外,其他非叶子节点至少有 m/2 个子节点。

    4、所有叶子节点都在同一层。

    6.1.3.8 B+ 树

    B+ 树是B树的变种。如下特征:

    1、多路平衡树

    2、只有叶子节点保存数据

    3、搜索时 也相当于二分查找

    4、增加了相邻叶子节点指针

    6.2 算法

    常见的算法如下:

    image-20210218160809562

    6.2.1 排序
    6.2.1.1 冒泡

    相邻的两个元素比较,左边大于右边则进行交换。时间复杂度O(n^2)。是稳定排序

    6.2.1.2 快排

    快速排序也属于交换排序,通过元素之间的比较和交换位置来达到排序的目的。每次选择一个基准元素,将比基准元素大的元素放到右边,比基准小的元素放到左边。然后分别对左右进行快排。是不稳定的排序

    6.2.1.3 堆排序

    堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。是不稳定的排序。

    7. 消息队列

    主流的消息队列有RabbitMQ、kafka、RocketMQ。三者各有优劣。RocketMQ 支撑高并发高可用的。

    7.1 消息队列的使用场景

    比如 创建订单减少库存、以及秒杀场景就可以使用消息队列。消息队列的使用,主要有三大优点:降低耦合、流量削峰填谷、异步。在一些不需要同步处理的场景,可以先把请求保存到消息队列中,直接返回结果给前端。提升响应速度。后续再进行消息的处理。如我们感知项目中,对没有接口日志都要进行日志入库的操作。我们之前是返回结果之前,将请求信息写入日志文件,后台线程定期执行入库。这样做将业务和日志入库进行了强耦合,进行了磁盘io ,接口的整体响应效率受到影响。后面引入 RocketMQ,接口再响应之前,向RocketMQ 中发送一条请求的消息后就返回给前端了。然后单独启用一个日志入库的服务消费RocketMQ 中的日志消息,进行日志入库。

    7.2 RocketMQ 的角色

    • Producer:消息的发送者;Producer与 NameServer 集群中的其中一个节点(随机选择)建立长连接,定期从 NameServer 获取 Topic 路由信息,并向提供Topic 服务的Master建立长连接,且定时向Master发送心跳。Producer完全无状态,可集群部署。

    • Consumer:消息接收者;Consumer与NameServer集群中的其中一个节点(随机选择)建立长连接,定期从NameServer获取Topic路由信息,并向提供Topic服务的Master、Slave建立长连接,且定时向Master、Slave发送心跳。Consumer既可以从Master订阅消息,也可以从Slave订阅消息,消费者在向Master拉取消息时,Master服务器会根据拉取偏移量与最大偏移量的距离(判断是否读老消息,产生读I/O),以及从服务器是否可读等因素建议下一次是从Master还 是Slave拉取。

    • Broker:暂存和传输消息;Broker分为Master与Slave,一个Master可以对应多个Slave,Master与Slave 的对应关系通过指定相同的BrokerName,不

      同的BrokerId来定义,BrokerId为0表示Master,非0表示Slave。Master也可以部署多个。每个Broker与NameServer集群中的所有节点建立长连接,定时注册Topic信息到所有NameServer。 注意:当前RocketMQ版本在部署架构上支持一Master多Slave,但只有BrokerId=1的从服务器才会参与消息的读负载。

    • NameServer:管理Broker;是一个几乎无状态节点,可集群部署,节点之间无任何信息同步。

    • Topic:区分消息的种类;一个发送者可以发送消息给一个或者多个Topic;一个消息的接收者可以订阅一个或者多个Topic消息

    • Message Queue:相当于是Topic的分区;用于并行发送和接收消息

    image-20210224105151502

    7.3 RocketMQ 的执行流程

    1、启动 NameServer,NameServer 起来后监听端口,等待 Broker、Producer、Consumer 连上来,相当于一个路由控制中心。

    2、Broker 启动,跟所有的 NameServer 保持长连接,定时发送心跳包。心跳包中包含当前 Broker 信息(IP+端口等)以及存储所有 Topic 信息。注册成功后,NameServer 集群中就有 Topic 跟 Broker 的映射关系。

    3、收发消息前,先创建 Topic,创建 Topic 时需要指定该 Topic 要存储在哪些 Broker上,也可以在发送消息时自动创建 Topic。

    4、Producer 发送消息,启动时先跟 NameServer 集群中的其中一台建立长连接,并从 NameServer 中获取当前发送的 Topic 存在哪些 Broker上,轮询从队列列表中选择一个队列,然后与队列所在的 Broker 建立长连接从而向 Broker 发消息。

    5、Consumer 跟 Producer 类似,跟其中一台 NameServer 建立长连接,获取当前订阅 Topic 存在哪些 Broker 上,然后直接跟 Broker 建立连接通道,开始消费消息

    7.4 RocketMQ 消息过滤

    RocketMQ 的消息过滤主要是在 consumer 端订阅消息时再做消息过滤的。主要基于 Tag 进行过滤。consumer 在订阅消息时,除了指定 topic 还可以指定 tag 。根据 tag 来过滤消息。

    7.5 零拷贝

    所谓的零拷贝就是数据在项目的虚拟内存和服务器的物理内存之间没有发生数据拷贝。正常的数据和磁盘的交互流程是。数据首先在项目的虚拟内存中,然后拷贝到物理内存,最后拷贝到磁盘上。读取的话先从磁盘到物理内存,再到项目的虚拟内存。使用零拷贝技术可以减少拷贝的次数。内存中不发生数据拷贝,提升数据传输效率。

    7.6 同步复制异步复制

    如果一个broker 组中存在master 和slave .消息需要从 master 同步到 slave.有同步复制和异步复制两种方式。

    同步复制:是等 master 和 slave 都写入成功后才返回客户端写成功状态。

    异步复制:只等 master 写入成功就返回。

    Master 角色的broker 支持读和写。slave 角色的broker 仅支持读。consumer 可以连接master 或者slave 进行消息的读取。

    7.7 刷盘机制

    RocketMQ 的所有消息都是持久化的,消息会先写入物理内存,然后刷盘保存到磁盘上。刷盘有同步刷盘和异步刷盘

    同步刷盘:同步刷盘等待消息保存到了磁盘后才返回。

    异步刷盘:消息保存到了物理内存就返回了。

    7.8 延时消息

    延时消息是指消息发送到 broker 后,不会立即被消费。而是等待特定的时间投递给真正的topic .一共有18个等级。可以通过messageDelayLevel 配置。最久延时2小时。

    7.9 事务消息

    RocketMQ 采用的是两阶段提交的方式实现事务消息。

    流程如下:

    1、发送方向RocketMQ发送“待确认”消息。

    2、RocketMQ将收到的“待确认”消息持久化成功后,向发送方回复消息已经发送成功,此时第一阶段消息发送完成。

    3、发送方开始执行本地事件逻辑。

    4、发送方根据本地事件执行结果向 RocketMQ 发送二次确认(Commit或是Rollback)消息。RocketMQ收到Commit状态则将第一阶段消息标记为可投递,订阅方将能够收到该消息;收到 Rollback 状态则删除第一阶段的消息,订阅方接收不到该消息。

    7.10 顺序消息

    实现顺序消息的话,只需要生产者只往一个队列中发送消息,并且发送模式调整为同步发送。这样就可以保证消费中从这个队列中消费的消息都是有序的。

    8. mysql

    8.1 mysql 体系架构

    mysql server 架构分为:网络连接层、服务层、存储引擎层、和系统文件层。

    image-20200830103406681

    网络连接层:客户端连接器提供与 mysql 服务端连接的支持。java、c、typhon 通过各自的 api 与 mysql 进行连接。

    服务层:系统管理和控制工具、连接池、SQL 接口、解析器、查询优化器、缓存。

    8.2 mysql 运行机制

    1、建立连接。mysql 客户端和服务端通信方式为半双工。也就是某一时刻,只能接受数据或者发送数据。

    2、查询缓存。先在缓存中查询是否有完全一致的 sql ,如果存在就直接将结果返回。

    3、解析器解析。解析器将 sql 进行语法解析,检测语法是否正确。

    4、查询优化器根据解析树生成最优的执行计划。

    5、查询存储引擎执行计划返回结果。

    8.3 mysql 存储引擎InnoDB

    InnoDB 支持事务、有行锁。支持多种索引。主要分为内存结构和磁盘结构两大部分。

    8.3.1 内存结构

    内存结构包含:buffer pool 、change buffer、log buffer、Adaptive Hash index 四部分。

    1、buffer pool(缓冲池)。以page 为基本单位,在InnoDB 访问表和索引时会在 Page 页中缓存,从而下次查询的时候从 缓冲池中查找,从而减少 磁盘的IO ,提升效率。

    2、change buffer(写缓存)。主要在进行增删改的操作是,如果 buffer pool 中没有对应的 Page 数据。并不会立刻从磁盘页中加载数据到缓存池,而是先在 change buffer 中记录下来,等下次数据读取时,再将数据合并到buffer pool 中。减少IO ,提升效率。

    3、Adaptive Hash Index (自适应哈希索引),用户优化对缓存池的查询。

    4、Log buffer(日志缓冲区)。用来保存要写入磁盘的 undo/redo 数据 。

    8.4 mysql 索引

    mysql 索引可以提升查询效率。有如下索引类型

    从应用层次划分:普通索引、唯一索引、主键索引、复合索引

    从数据存储和索引键值逻辑关系划分:聚集索引(聚簇索引)、非聚集索引(非聚簇索引)

    8.4.1 普通索引

    最普通的索引类型,基于普通字段简历的索引,没有任何限制。

    8.4.2 唯一索引

    和普通所以的区别,索引字段的值必须唯一,但是可以为空值。

    8.4.3 主键索引

    它是一种特殊的索引,不允许有空值,且字段值必须唯一。一张表只能有一个主键,也只能有一个主键索引。

    8.4.4 复合索引

    复合索引是对表的多个字段创建的联合索引。

    如果表已经建立了(col1,col2),就没有必要再单独建立(col1);如果现在有(col1)索引,如果查询需要col1和col2条件,可以建立(col1,col2)复合索引,对于查询有一定提高。

    8.4.5 聚集索引

    B+树叶子节点存放的索引值和行记录就属性聚集索引,如果叶子节点只存储了索引值和主键 那就是非聚集索引。

    简单说不需要回表查询的就是聚集索引,需要回表查询的就是非聚集索引。主键索引就是聚集索引。

    8.4.6 索引原理

    Mysql 索引采用的是B+ 树的数据结构。

    1、非叶子节点不存储数据,值存储索引值。

    2、叶子节点包含在同一层,包含所有的索引值和数据。

    3、相邻的叶子节点通过指针连接,提高区间访问性能。

    8.4.7 like 查询

    MySQL 在使用 Like 模糊查询时,索引是可以被使用的,只有把%字符写在后面才会使用到索引。

    8.4.8 explain 有哪些字段

    1、select_type 表示查询类型。常用值有SIMPLE

    2、type 表示存储引擎查询数据时采用的方式。ALL 全表查询、index 基于索引的全表扫描、range 范围查询、ref 索引查询。

    3、possible_keys 表示查询时能够使用到的索引。

    4、key:表示查询时真正使用到的索引,显示的是索引名称。

    8.4.9 慢查询优化

    先分析慢查询的原因:

    1、全表扫描

    2、全索引扫描

    3、索引过滤性不好

    4、频繁的回表查查询

    如果没有使用索引就创建所以,如果索引效率不高,就优化索引,最好使用覆盖索引。避免回表查询。

    8.5 mysql 锁

    8.5.1 锁分类

    在 MySQL中锁有很多不同的分类

    • 从操作的粒度可分为表级锁、行级锁和页级锁。

      • 表级锁:每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低。应用在MyISAM、InnoDB、BDB 等存储引擎中。
      • 行级锁:每次操作锁住一行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高。应用在InnoDB 存储引擎中。
      • 页级锁:每次锁定相邻的一组记录,锁定粒度界于表锁和行锁之间,开销和加锁时间界于表锁和行锁之间,并发度一般。应用在BDB 存储引擎中。
    • 从操作的类型可分为读锁和写锁

      • 读锁(S锁):共享锁,针对同一份数据,多个读操作可以同时进行而不会互相影响。
      • 写锁(X锁):排他锁,当前写操作没有完成前,它会阻断其他写锁和读锁。
    • 从操作的性能可分为乐观锁和悲观锁。

      • 乐观锁:一般的实现方式是对记录数据版本进行比对,在数据更新提交的时候才会进行冲突检测,如果发现冲突了,则提示错误信息。
      • 悲观锁:在对一条数据修改的时候,为了避免同时被其他人修改,在修改数据之前先锁定,再修改的控制方式。共享锁和排他锁是悲观锁的不同实现,但都属于悲观锁范畴。
    8.5.2 悲观锁

    悲观锁(Pessimistic Locking),是指在数据处理过程,将数据处于锁定状态,一般使用数据库的锁机制实现。从广义上来讲,前面提到的行锁、表锁、读锁、写锁、共享锁、排他锁等,这些都属于悲观锁范畴。

    表锁:表级读锁会阻塞写操作,但是不会阻塞读操作。而写锁则会把读和写操作都阻塞。

    共享锁:是行锁-读锁,事务使用了共享锁(读锁),只能读取,不能修改,修改操作被阻塞。

    排它锁:是行锁-写锁。事务使用了排他锁(写锁),当前事务可以读取和修改,其他事务不能修改,也不能获取记录

    8.5.3 乐观锁

    乐观锁是相对于悲观锁而言的,它不是数据库提供的功能,需要开发者自己去实现。在数据库操作时,想法很乐观,认为这次的操作不会导致冲突,因此在数据库操作时并不做任何的特殊处理,即不加锁,而是在进行事务提交时再去判断是否有冲突了。

    乐观锁实现的关键点:冲突的检测。

    悲观锁和乐观锁都可以解决事务写写并发,在应用中可以根据并发处理能力选择区分,比如对并发率要求高的选择乐观锁;对于并发率要求低的可以选择悲观锁。

    实现方式:添加版本和时间戳

    8.5.4 死锁

    死锁产生的四个必要条件:

    互斥条件:一个资源同一时刻只能被一个进程占用。

    不可剥夺:一个资源除非被占用的进程主动释放,否则不能被剥夺

    请求保持:一个进行请求资源时,没有获取到则保持请求,直到获取资源

    循环等待:进程a 等待进程b 持有的资源,进程b 等待进程a 持有的资源

    破坏其中一个条件就可以避免死锁。

    8.6 mysql 事务

    8.6.1 事务特性

    mysql 事务有4个特性,即所谓的 ACID:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。

    原子性:事务是一个原子操作单元,对数据的修改,要么全都执行,要么全都不执行。

    一致性:是指事务在开始前和事务结束后,数据库的完整性限制没有被破坏。

    隔离性:是指一个事务的执行,不会被其他事务干扰,一个事务的内部操作及使用的数据对其他的并发事务是隔离的。

    持久性:指事务一旦提交,它对数据库中的数据修改时永久性的,后续操作不会对其有任何影响,不会丢失。

    8.6.2 事务隔离级别

    数据库系统提供了以下 4 种事务隔离级别

    • 读未提交:解决了回滚覆盖类型的更新丢失,但可能发生脏读现象(一个事务读取到了另一个事务修改但未提交的数据),也就是可能读取到其他会话中未提交事务修改的数据。

    • 已提交读:只能读取到其他会话中已经提交的数据,解决了脏读。但可能发生不可重复读现象(一个事务中多次读取同一行记录不一致,后面读取的跟前面读取的不一致),也就是可能在一个事务中两次查询结果不一致。

    • 可重复度:解决了不可重复读,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上会出现幻读(一个事务中多次按相同条件查询,结果不一致。后续查询的结果和面前查询结果不同,多了或少了几行记录),简单的说幻读指的的当用户读取某一范围的数据行时,另一个事务又在该范围插入了新行,当用户在读取该范围的数据时会发现有新的幻影行。

    • 可串行化:所有的增删改查串行执行。它通过强制事务排序,解决相互冲突,从而解决幻度的问题。这个级别可能导致大量的超时现象的和锁竞争,效率低下

    8.6.3 MVCC

    多版本控制,支持读读、读写、写读并行。但为了保证一致性,写写是无法并行的。

    在事务1开始写操作的时候会copy一个记录的副本,其他事务读操作会读取这个记录副本,因此不会影响其他事务对此记录的读取,实现写和读并行。

    8.7 mysql 分库分表

    使用分库分表时,主要有垂直拆分和水平拆分两种拆分模式,都属于物理空间的拆分。

    垂直拆分:由于表数量多导致的单个库大。将表拆分到多个库中。

    水平拆分:由于表记录多导致的单个库大。将表记录拆分到多个表中。

    8.7.1 主键策略

    1、uuid

    2、雪花片算法。ID 按照时间有序生成。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号,最后还有一个符号位,永远是0

    3、redis 生成id.利用 redis 的原子操作 INCR 来实现。

    8.7.2 分片策略

    1、范围分片

    2、hash 取模分片

    3、一致性hash 分片

    8.8 mysql 主从同步

    8.8.1 适用场景

    MySQL 主从模式是指数据可以从一个 MySQL 数据库服务器主节点复制到一个或多个从节点。MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,从节点可以复制主数据库中的所有数据库,或者特定的数据库,或者特定的表。

    8.8.2 主从同步作用

    1、实时灾备,用于故障切换

    2、读写分离,提供查询服务

    3、数据备份,避免影响业务(高可用)

    8.8.3 主从同步实现原理

    主要分为三个步骤

    1、主库将数据库的变更记录到Binlog 日志文件中

    2、从库读取主库的 Binlog 日志文件信息写入到从库的 Ready log 日志中。

    3、从库读取 Ready Log 日志信息在从库中 Replay ,更新从库信息

    异步复制:master 不会等待slave 节点返回,直接提交事务,会导致数据不一致。

    半同步复制:master 会等待slave 节点的ack 消息后才会进行事务提交。

    9. redis

    9.1 跳跃表

    跳跃表是有序集合的底层实现。就是将有序集合的部分节点进行分层。每一层都是有序集合,并且层次越高,节点数量就越少。最底层的包含所有节点数据。典型的空间换时间。

    9.2 字典

    字典是 redis 用来存储键值对的一种数据结构。

    hash 函数: 把redis 的key(字符串、整型、浮点型)统一转换成统一长度的整数。

    hash 冲突:采用单链表解决。

    字典扩容:新申请的容量为原来的一倍,将老的数据迁移到新字典中需要rehash。比较缓慢。

    9.3 压缩列表

    由一系列特殊编码的连续内存块组成的顺序型数据结构。没有压缩列表包头部、entry数据和尾部。头部信息包含压缩列表的字节长度、压缩列表尾部元素的偏移量、压缩列表元素个数;尾部为一个字节,为结束标志。

    entry 数据包含:前一个元素的字节长度、当前元素的编码、以及当前元素的数据内容。

    9.4 快速列表

    quicklist 是列表的底层实现。quicklist 是一个双向链表,同时每个节点是一个压缩列表。这样quicklist 的每个节点都可以存储多个元素。

    9.5 缓存过期和淘汰策略

    9.5.1 过期删除策略

    redis 淘汰策略有三种。定时删除、惰性删除和主动删除。

    Redis 目前采用惰性删除和主动删除。

    9.5.1.1 定时删除

    在设置键的过期时间时,创建一个定时器,让定时器在该键过期时,执行对键的删除操作。(需要创建定时器,消耗cpu)

    9.5.1.2 惰性删除

    在访问 key 的时候发现它失效了,就删除这个key

    9.5.1.3 主动删除(定期删除)

    每隔一段时间,我们就对一些key 进行检查,删除过期的 key

    9.5.2 淘汰策略
    9.5.2.1 LRU

    LRU (Least recently used )最近最少使用。基于链表实现,每次新数据插入到链表头部,如果链表中的节点有被用到,就将该节点移到链表头部。这样链表尾部的元素就是最近最少使用的了。删除的 时候从尾部开始删除。

    volatile-lru:从已经设置过期的数据集中挑选最近最少使用的进行数据淘汰。

    allkeys-lru:从所有数据集中挑选最近最少使用的数据进行淘汰。

    9.5.2.2 随机

    从数据集中任意选择一个数据淘汰

    9.5.2.3 volatile-ttl

    从已经设置过期时间的数据集中挑选将要过期的数据进行淘汰。从过期时间表中随机挑选几个键值对,取出其中ttl 最小的键值对进行淘汰。

    9.6 缓存穿透、缓存雪崩、缓存击穿

    9.6.1 缓存穿透

    缓存穿透是指在高并发下查询 key 不存在数据,会穿透缓存查询数据库,导致数据库压力过大而宕机。

    解决方案:

    一:设置一个短暂的随机延时,避免同一时刻所有的请求都穿过缓存增大数据的压力。这样先从数据库查询的数据查询出后,添加到缓存中,其他的请求就不会从数据库中请求了。

    二:设置布隆过滤器,在缓存之前再加一个层布隆过滤器,在查询的时候先去布隆过滤器中查询key 是否存在,如果不存在就直接返回,如果存在再查询缓存和DB.

    布隆过滤器的原理是一组hash函数。当一个元素被加入集合中时,通过k个 hash 函数将这个元素映射成一个数据中的k个点,把他们置为1。检索是,我们只要看看这些点是不是1就知道集合中存不存在这个元素了。只要有一个点为0,则被检测的元素一定不存在集合中。

    9.6.2 缓存雪崩

    大量缓存集中在某一时间段内失效,这样在失效的时候,大量请求达到数据库,造成数据库崩溃。

    解决方案:

    1、key 的失效期分散开,不同的key 设置不同的有效期。

    2、设置二级缓存

    3、搭建集群。单节点故障后,由从节点补上。

    9.6.3 缓存击穿

    主要针对热点数据,当key 在某一时间点过期的时候,正好有大量的并发请求访问这个key。从而请求都达到数据库,加大的数据库压力。

    解决方案:

    1、针对热点 key.不设置超时时间。定期的充数据库同步到redis 中。

    2、用分布式锁控制访问的线程。使用redis 的setnx互斥锁进行判断,只有获取锁的线程才能访问数据库,其他的线程进行等待。

    9.7 单线程的Redis 为什么这么快

    1、正常情况下都是内存操作,不会和磁盘交换,从而访问速度更快。

    2、单线程没有锁,没有多线程的切换和调度,不会死锁,没有性能损耗。

    3、采用I/O 多路复用模型,非阻塞io 。效率更高

    4、数据结构简单,压缩处理。

    9.8 redis 分布式锁实现

    加锁:使用setnx 加锁,如果执行成功,然后设置过期时间。

    解锁:删除加锁的key

    10. 中间件

    10.1 zookeeper

    10.1.1 zookeeper 数据结构

    zookeeper 将所有的数据存储在内存中,数据模型是一个Znode tree。用斜杠分割路径,每个znode 上还保留自己的数据内容,同时保留一系列的属性信息。

    在这里插入图片描述

    可以根据需求创建如下四种类型的节点:

    持久节点:在节点创建后,会一直存在服务器上,直到删除操作主动删除。

    持久顺序节点:和持久节点一样,创建后就一直存在,并且多了一个特性,在创建节点的时候,会加上一个数字后缀,来表示顺序。

    临时节点:它的生命周期和客户端会话绑定在一起,客户端会话结束,节点就会被删除掉。如持续节点不同的是,临时节点不能创建子节点。

    临时顺序节点:有顺序的临时节点,相对于临时节点而言,在创建的时候,会加一个数字后缀,表示顺序。

    10.1.2 监听器

    Watcher(事件监听器)是zookeeper 中一个重要的特性,zookeeper 允许用户在指定的节点上注册一些watcher。并在一些特定的事件触发的时候,zookeeper 服务端会将事件通知到感兴趣的客户端。

    10.1.3 zookeeper 应用场景

    1、数据发布订阅

    2、集群管理

    3、分布式锁。利用zookeeper 可以实现分布式锁的排它锁和共享锁。

    排他锁:利用zk 的强一致性,以及临时节点的特性。首先定义一二锁节点。然后多线程在锁节点下创建一个临时节点,哪个节点创建成功了,就说明该线程获取到了分布式锁,没有获取到锁的线程,就注册一个所节点的子节点监听事件,以便监听到锁节点的变化情况。如果一个线程执行完成或者执行异常,都会关闭连接,表示释放了锁,这样其他节点就可以通过监听事前来重新获取锁了。

    共享锁:一样的是利用zk 节点的强一致性。不过创建的是顺序的临时节点。分别表示读锁和写锁。对于读请求,如果没有比自己小的节点或者所有比自己小的节点都是读请求,那么表明自己已经成功的获取到了共享锁,开始执行读取逻辑。对于写请求,如果自己不是序号最小的节点,就需要等待。

    4、分布式队列

    10.1.4 ZAB 协议

    在 zookeeper 中主要是利用原子广播协议来保证数据一致性的。

    ZAB 协议的核心是定义了对于那些会改变 Zookeeper 服务器数据状态的事务请求的处理方式
    即:所有事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被称为Leader服务器,余下的服务器则称为Follower服务器,Leader服务器负责将一个客户端事务请求转化成一个事务Proposal(提议),并将该Proposa1分发给集群中所有的Follower服务器,之后Leader服务器需要等待所有Follower服务器的反馈,一旦超过半数的Follower服务器进行了正确的反馈后,那么Leader就会再次向所有的Follower服务器分发Commit消息,要求其将前一个Proposal进行提交。

    image-20200720181011476

    10.2 dubbo

    在集群负载均衡时,dubbo 提供了多种均衡策略。包含随机、轮询、最小活跃调用数、一致性hash。 默认为随机调用。

    11. 分布式

    11.1 分布式下读写一致性

    用户读取自己结果的一致性。保证用户永远能够第一时间看到自己更新的内容。

    如:我们发朋友圈,别人能不能第一时间看到没关系,但是需要我们自己第一时间就能看到,这个应该怎么实现?

    解决方案:

    1、我们设置一个更新时间窗口,在刚刚更新的这段时间内,我们默认都从主库读取,过了这个窗口后,挑选最近有从主库更新的从库读取。

    2、我们直接记录用户操作的时间戳。在请求的时候,直接把这个时间戳带上,凡是最后更新时间小于这个时间戳的分库就不予以响应。

    11.2 单调一致性

    本次读取到的数据不能比上次读取到的数据旧。

    解决方案:

    根据用户id 计算hash 值,映射到对应的服务器上,这样同一个用户不管怎样刷新,都会被映射到同一台机器,保证不会出现数据变旧的情况。

    11.3 CAP 理论

    一个分布式系统不能同时满足一致性、可用性、分区容错性这三个基本需求,只能满足其中两个。

    11.4 BASE 理论

    BASE 由三个单词组成。基本可用(Basically Available)、软状态(Soft state)、最终一致性(Eventually consistent)。核心是想是:即使无法做到强一致性,但是每个应用都可以根据自己的特点,采用适当的方式来使得系统达到最终一致性。

    11.5 2PC 和 3PC

    两阶段提交协议:分为准备阶段和提交阶段。在准备阶段,事务管理器会给每个参入者发送prepare 消息,每个参数者在自己本地执行事务,并写入undo/redo 日志(undo 是修改前的日志,用于事务回滚,redo是修改后的日志,用来数据提交),这个时候事务还没有提交。在提交阶段,如果事务管理器收到了参入者执行失败或者超时的消息时,会发送回滚的消息给所有参入者进行回滚。如果都成功了,就发送提交的消息给所有参入者进行数据提交操作。

    三阶段提交协议:是将2PC 的提交阶段一分为二。precommit 阶段发送预提交请求,各个参入者向协调者反馈执行结果。docommit 阶段执行事务提交。

    11.6 paxos 一致性算法

    paxos 算法核心就是提案。

    1、proposer 选择一个提案为N ,向半数以上的Acceptor 发送编号为N 的 prepare 请求。

    2、如果 Acceptor 收到一个编号为N的 prepare请求,并且N为当前Acceptor 所响应的请求中编号最大的,它就接收这个提案,并且不再接收比这个编号更小的提案了。

    3、如果proposer 收到了半数以上Acceptor 对其发出的编号为N 的prepare请求响应。就会给半数以上的 Acceptor 发送提案的accept 请求。

    4、如果acceptor 收到一个编号为N的accept 请求,如果当前acceptor 没有对编号大于N 的prepare 请求做出响应,它就接收该提案。

    11.7 Raft 一致性算法

    Raft 一致性算法分为两个阶段:首先是选举阶段,然后通过选举出来的领导人带领进行正常操作。

    选举的过程:

    1、集群中所有的节点开始的时候都是 follower 跟随者。当发现没有领导者的时候,

    2、部分的跟随者会变成候选者,候选者会向跟随者发起投票请求。如果当前候选者获得了超过半数的选票,就自动变成了领导者。

    3、如果集群中存在领导者,其他的候选者也会变成跟随者,所有的跟随者都会从领导者中进行数据同步,保证数据一致性。

    12. mybatis

    12.1 mybatis 初始化

    1、通过jdk 文件流加载器读取xml配置文件。

    2、通过XmlConfigBuilder 来解析配置文件,并封装到configuration 对象中。

    3、创建SqlSessionFactory 对象,并传递configuration

    4、通过SqlSessionFactory.openSqlSession() 来创建sqlSession 对象并返回。

    12.2 sql 执行过程

    1、通过调用Sqlsession 对象的query()或者update() 方法。

    2、通过statmentid 从configuration 中获取到对应的mapperstatement

    3、将configuration 和mapperstatement 对象传递给Executor 执行器来执行sql 操作。

    4、Executor 执行器用来处理缓存,以及动态sql 的生成,并将sql 传递给statementhandle

    5、statementHandle 将调用parameterHandle 进行参数的解析

    6、statementHandle 执行sql 得到结果。

    7、statementHandle 通过ResultSetHandle 将返回的结果进行对象映射,最终返回结果。

    12.3 mybatis 插件

    mybatis 作为应用广泛的优秀的ORM开源框架,具有强大的扩展性,在mybatis 中的 Executor、StatementHandle、ParameterHandle、ResultSet 这四大组件提供了简易的拓展支持。mybatis 支持插件对上面这四大对象进行拦截,从而实现前置增强和后置增强。

    自定义插件只需要实现mybatis 的interceptor 接口,并通过注册来声明拦截的类和方法。

    展开全文
  • java面试宝典

    2019-03-27 16:07:36
    Java面试宝典》着力于java程序员可能会被面试官问道题目,并对求职中签约、毁约的注意事项及群体面试进行了解析。《Java面试宝典》的面试题除了有详细的解析外,对相关知识点也有扩展说明。希望这些内容对读者从...
  • Java面试宝典(2019版)

    万次阅读 多人点赞 2019-05-23 09:35:07
    Java/C/C++/机器学习/算法与数据结构/前端/安卓/Python/程序员必读书籍书单大全: 书单导航页(点击右侧 极客侠栈 即可打开个人博客):极客侠栈 ①【Java】学习之路吐血整理技术书从入门到进阶最全50+本(珍藏版...

    附Java/C/C++/机器学习/算法与数据结构/前端/安卓/Python/程序员必读书籍书单大全:

    书单导航页(点击右侧 极客侠栈 即可打开个人博客):极客侠栈
    【Java】学习之路吐血整理技术书从入门到进阶最全50+本(珍藏版)
    【算法数据结构+acm】从入门到进阶吐血整理书单50+本(珍藏版)
    【数据库】从入门到进阶必读18本技术书籍网盘吐血整理网盘(珍藏版)
    【Web前端】从HTML到JS到AJAX到HTTP从框架到全栈帮你走更少弯路(珍藏版)   
    【python】书最全已整理好(从入门到进阶)(珍藏版)

    【机器学习】+python整理技术书(从入门到进阶已经整理好)(珍藏版)
    【C语言】推荐书籍从入门到进阶带你走上大牛之路(珍藏版)
    【安卓】入门到进阶推荐书籍整理pdf书单整理(珍藏版)

    【架构师】之路史诗级必读书单吐血整理四个维度系列80+本书(珍藏版)

    【C++】吐血整理推荐书单从入门到进阶成神之路100+本(珍藏)

    【ios】IOS书单从入门到进阶吐血整理(珍藏版)

    -------------------------------------------------------------------------------------------------------------------------------------------

    此内容偏中高级,适合有三年经验者。

    1.       java中wait和sleep有什么区别?多线程条件下如何保证数据安全?

       答:最大区别是等待时wait会释放锁,而sleep会一直持有锁,wait通常用于线程时交,互,sleep通常被用于暂停执行。

    2.       java中volatile和synchronized有什么区别?

    1.volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
    2.volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。
    3.volatile仅能实现变量的修改可见性,并不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。
    4.volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。 
    5.volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。
    3.       有了解java的原子类?实现原理是什么?

             答:采用硬件提供原子操作指令实现的,即CAS。每次调用都会先判断预期的值是否符合,才进行写操作,保证数据安全。

     

    4.       spring主要使用了哪些?IOC实现原理是什么?AOP实现原理是什么?

      答:spring主要功能有IOC,AOP,MVC等,IOC实现原理:先反射生成实例,然后调用时主动注入。AOP原理:主要使用java动态代理,

    5.       mybatis有了解吗?它与hibernate有什么区别?项目中,你会选哪个?

     答:两者都是轻量级ORM框架,hibernate实现功能比较多,通过HQL操作数据库,比较简单方便,但hibernate自动生成的sql相长,不利测试和查找原因。复杂sql时,编写比较困难,同时性能也会降低。mybatis是半自动化,手动编写SQL语句,同时提供丰富的参数判断功能。sql语句较清晰,可以直接进行测试,性能也较好,操作起来非常简单。同时hibernate容易产生n+1问题。hibernate学习成本较mybatis高。国内一些大公司基本上使用mybatis

     

    6.       缓存框架有使用过哪些?memcache和redis有什么区别?项目中,怎么去选择?

            答:缓存有:ehcache,memcache和redis等

             区别:

             1、 Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过        memcache还可用于缓存其他东西,例如图片、视频等等。

             2、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的   存储。

             3、虚拟内存--Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘

             4、过期策略--memcache在set时就指定,例如set key1 0 0 8,即永不过期。Redis可以通 过例如expire 设定,例如expire name 10

             5、分布式--设定memcache集群,利用magent做一主多从;redis可以做一主多从。都     可以一主一从

             6、存储数据安全--memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化)

             7、灾难恢复--memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复

             8、Redis支持数据的备份,即master-slave模式的数据备份。

     

             项目使用选择:

             redis是单线程实现,若需要使用控制某些并发状态时,可以使用redis.项目中需要使用 复杂的list,set操作时,同时可以对数据进行持久化。

             当存储数据较大时,如100k以上,那memcache性能较好,在多核上,memcache较     好

    7.       说说数据库性能优化有哪些方法?

             答:使用explain进行优化,查看sql是否充分使用索引。避免使用in,用exist替代,字段值尽可能使用更小的值,任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。使用连接查询(join)代替子查询。

    在表的多列字段上建立一个索引,但只有在查询这些字段的第一个字段时,索引才会被使用。

    8.       HTTP请求方法get和post有什么区别?

                        1:Post传输数据时,不需要在URL中显示出来,而Get方法要在URL中显示。

                      2:Post传输的数据量大,可以达到2M,而Get方法由于受到URL长度限制,只能                   传递大约1024字节.

                     3:Post就是为了将数据传送到服务器段,Get就是为了从服务器段取得数据.而Get                      之所以也能传送数据,只是用来设计告诉服务器,你到底需要什么样的数据.Post                   的信息作为http请求的内容,而Get是在Http头部传输的。

    9.       linux命令熟悉?查看某个线程命令是什么?查看整个机器负载命令?文件内容快速查找命令是什么?

             查看线程:ps -ef|greptomcat

             查看负载:top

             文件内容查找:vi  /aa test.txt 或者先打开文件,再查找: vi test.txt   /aa

    10.  JVM内存模型是如何?垃圾回收机制有哪些?如何对JVM进行调优?

             答:由栈和堆组成,栈是运行时单位,堆内存则分为年轻代、年老代、持久代等,年轻代中的对象经过几次的回收,仍然存在则被移到年老代;持久代主要是保存class,method,filed等对象。

    sun回收机制:主要对年轻代和年老代中的存活对象进行回收,分为以下:

    年轻代串行(Serial Copying)、年轻代并行(ParNew)、年老代串行(SerialMSC),年老代并行(Parallel Mark Sweep),年老代并发(Concurrent Mark-Sweep GC,即CMS)等等,目前CMS回收算法使用最广泛。

    JVM调优主要是对堆内容和回收算法进行配置,需要对jdk产生的回收日志进行观察,同时通过工具(Jconsole,jProfile,VisualVM)对堆内存不断分析,这些优化是一个过程,需要不断地进行观察和维护。

     

          

    11.  如银行内部转账功能,如何保证数据一致性,即要么同时成功,要么同时失败?高并发时,又如何保证性能和数据正确?

           答:如果是单机内完成这些操作,那使用数据库的事务,即可轻松实现。若是分布式呢?

    12.  有了解分布式事务如何实现?

             答:分布式事务可以采用分布式锁进行实现,目前zookeeper就提供此锁;分布式锁需要牺牲一定性能去实现,若业务支付最终一致性,那此方法是最佳方案。如在京东下订单,过一会才会告诉你订单审核通过,而不是马上响应订单结果。

    13.  java抽象类和接口有什么区别?项目中怎么去使用它们?

             相同点:

             A. 两者都是抽象类,都不能实例化。

             B. interface实现类及abstractclass的子类都必须要实现已经声明的抽象方法。

           不同点:

             A. interface需要实现,要用implements,而abstractclass需要继承,要用extends。

             B. 一个类可以实现多个interface,但一个类只能继承一个abstractclass。

             C. interface强调特定功能的实现,而abstractclass强调所属关系。

             D. 尽管interface实现类及abstrctclass的子类都必须要实现相应的抽象方法,但实现的         形式不同。interface中的每一个方法都是抽象方法,都只是声明的 (declaration, 没有方         法体),实现类必须要实现。而abstractclass的子类可以有选择地实现。

            

             使用:

             abstract:在既需要统一的接口,又需要实例变量或缺省的方法的情况下,使用abstract;

             interface:使用: 类与类之前需要特定的接口进行协调,而不在乎其如何实现。 作为能          够实现特定功能的标识存在,也可以是什么接口方法都没有的纯粹标识。需要将一组类     视为单一的类,而调用者只通过接口来与这组类发生联系。需要实现特定的多项功能,         而这些功能之间可能完全没有任何联系。

    14.  对socket熟悉?TCP通讯有几次握手?有使用过哪些socket框架?

             答:3次握手,客户端-->服务端,服务端-->客户端,客户端-->服务端,当这些过程完成之后,才真正建立起通信。java中比较有名的socket框架有:mina,netty,都是韩国小棒子写的。

    15.  了解java反射机制?反射生成类,能访问私有变量?

           答:即动态生成java的实例,可以

    16.  RPC是什么?有使用过哪些RPC框架?

           答:即远程进程调用,本地机器调用远程的服务,在项目规模大到一定程度,需要使用RPC相关框架进行服务化部署。如:hessian 、webservice等

    17.  熟悉js或css?jquery如何绑定页面某元素的点击事件?

    答:$("#btn").click(function(){

    })
     

    展开全文
  • java 面试宝典

    2019-03-31 01:30:03
    NULL 博文链接:https://dengminghua1016.iteye.com/blog/1346768

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,843
精华内容 2,337
关键字:

java面试宝典

java 订阅