面试总结
一、SpringBoot
Spring boot是一个脚手架(而非框架),构建于spring框架(Framework)基础之上,基于快速构建理念,提供了自动配置功能,可实现其开箱即用特性(创建完一个基本的项目以后,可以零配置或者少量配置即可运行我们的项目),其核心主要有如下几个方面:
起步依赖(Starter Dependency)
自动配置(Auto Configuration)
健康检查(Actator)-监控
1. 项目启动过程分析
Spring Boot项目在启动时,首先基于启动入口类上的注解描述,进行自动配置并扫描指定包以及子包中的类进行加载,然后检测类上是否有spring框架中指定的注解描述(例如@Component,@Controller,@Service等)。假如有,则将类交给Spring框架中的Bean Factory工厂接口的实现类对象,此工厂对象会基于反射创建Bean的实例,假如此Bean指定了生命周期方法,还会调用生命周期方法。当实例创建以后,Spring框架还会基于类的作用域描述,将实例存储到不同作用域的容器中。以实现Bean对象的科学应用
2. 注解描述
@Lazy注解用于描述类,其目的是告诉spring框架此类支持延迟加载,通常会配合单例作用域使用。
@PostConstruct注解用于描述bean对象生命周期方法中的初始化方法,此方法会在对象的构造方法之后执行
@PreDestroy注解用于描述Bean对象生命周期方法中的销毁方法,此方法会在对象销毁之前执行(当作用域为prototype时,此方法不会执行)
3. SpringBoot整合连接池
实际开发中应用程序与数据库交互时,“获得连接”或“释放资源”是非常销毁资源的两个过程,为了解决此类性能问题,通常情况我们采用连接池技术来重用连接Connection对象
用户通过DataSource对象的getConnection()方法,获取一个连接。假如池中有连接,则直接将连接返回给用户。假如池中没有连接,则会调用Driver(驱动,由数据库厂商进行实现)对象的connect方法从数据库获取,拿到连接以后,可以将连接在池中放一份,然后将连接返回给调用方。
二、Spring
1. 什么是Spring
Spring是一个资源整合框架(Framework),通过spring可将很多资源(自己写的对象或第三方提供的对象,例如连接池等)整合在一起,然后进行科学应用,以便更好的对外提供服务。
Spring框架可以为由他管理的对象(Bean)提供懒加载策略(对象暂时用不到,则无需加载和实例化),作用域(例如singleton-频繁用时可以考虑内存中只有一份,prototype-使用次数少时可以用时创建,不用时销毁),生命周期方法(更好实现对象的初始化和资源销毁),以实现对系统资源的有效使用。同时spring框架还可以基于用户设计管理对象与对象的依赖关系,以降低对象与对象之间的直接耦合,提高程序可维护性和可扩展性
2. Spring的优势
1).方便解耦,简化开发
通过 Spring提供的 IoC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为较为底层的需求编写代码,可以更专注于上层的应用。
2).AOP 编程的支持
通过 Spring的 AOP 功能,方便进行面向切面的编程,许多不容易用传统OOP(Object Oriented Programming:面向对象编程) 实现的功能可以通过 AOP 轻松应付。
3).声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发效率和质量。
4).方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情。
5).方便集成各种优秀框架
Spring可以降低各种框架的使用难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、Quartz等)的直接支持。
6).降低 JavaEE API 的使用难度。
Spring对 JavaEE API(如 JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些API 的使用难度大为降低。
7).Spring框架源码是经典学习范例
Spring的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对Java设计模式灵活运用以及对 Java技术的高深造诣。它的源代码无疑是Java技术的最佳实践的范例。
3. spring的架构
Spring 最初的目标就是要整合一切优秀资源,然后对外提供一个统一的服务。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式,如下图所示:
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
模块说明
核心容器Spring Core核心容器,提供Spring框架的基本功能。核心容器的主要组件是BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC)模式,将应用程序的配置和依赖性规范与实际的应用程序代码分开。
Spring ContextSpring上下文,是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring AOP通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能集成到了 Spring 框架中。可以很容易地使 Spring框架管理的任何对象支持AOP。Spring AOP模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,就可以将声明性事务管理集成到应用程序中。
Spring DAOJDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
Spring ORMSpring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括JDO、Hibernate和iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
Spring WebWeb上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以Spring 框架支持与 Jakarta Struts的集成。Web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
Spring MVC框架MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
4. 什么是程序的耦合
耦合性(Coupling) ,也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。 模块间联系越多,其耦合性越强 ,同时表明其独立性越差(降低耦合性,可以提高其独立性)。耦合性存在于各个领域,而非软件设计中独有的,但是我们只讨论软件工程中的耦合。
总结:在软件工程中, 耦合指的就是指对象之间的依赖关系。对象之间的依赖程度越高,耦合度就越高。对象之间的耦合越高,维护成本越高 。因此对象的设计应使类和构件之间的耦合最小。
降低程序之间的依赖程度,即降低程序之间的耦合度的过程就叫做解耦。
5. SpringIOC控制反转
什么是控制反转
控制反转 (Inversion of Control,缩写为 IOC ),即,把创建对象的权利交给框架。 也就是指将对象的创建、对象的存储、对象的管理交给了spring容器(spring容器是spring中的一个核心模块,用于管理对象,底层可以理解为是一个map集合)
三、MyBatis
1. 什么是MyBatis
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
总之,Mybatis对JDBC访问数据库的过程进行了封装,简化了JDBC代码,解决JDBC将结果集封装为Java对象的麻烦。
下图是MyBatis架构图:
mybatis-config.xml是Mybatis的核心配置文件,通过其中的配置可以生成SqlSessionFactory,也就是SqlSession工厂
基于SqlSessionFactory可以生成SqlSession对象
(3)SqlSession是一个既可以发送SQL去执行,并返回结果,类似于JDBC中的Connection对象,也是Mybatis中至关重要的一个对象。
Executor是SqlSession底层的对象,用于执行SQL语句
MapperStatement对象也是SqlSession底层的对象,用于接收输入映射(SQL语句中的参数),以及做输出映射(即将SQL查询的结果映射成相应的结果)
四、SpringMVC
MVC设计模式
MVC设计模式是一种通用的软件编程思想
在MVC设计模式中认为, 任何软件都可以分为三部分组成:
控制程序流转的控制器( Controller )
封装数据处理数据的模型( Model )
负责展示数据的视图( view )
并且在MVC设计思想中要求一个符合MVC设计思想的软件应该保证上面这三部分相互独立,互不干扰,每一个部分只负责自己擅长的部分。
如果某一个模块发生变化,应该尽量做到不影响其他两个模块。这样做的好处是,软件的结构会变得更加的清晰,可读性强。有利于后期的扩展和维护,并且代码可以实现复用
Servlet充当MVC中的Controller,负责调用model处理业务,负责转发或重定向某个页面,在页面(view)上呈现数据
模块封装了对Servlet的技术的应用,简化了程序员对请求和响应过程中数据的处理。
SpringMVC是Spring框架中基于MVC设计思想实现的一个用于处理web请求的模
DispatcherServlet: 前端控制器,处理请求的入口
Handler Mapping:映射器对象,用于管理url与对应controller的映射关系
Interceptors: 拦截器,实现请求响应的共性处理
Controller:后端控制器-handler,负责处理请求的控制逻辑。
ViewResolver:视图解析器,解析对应的视图关系(前缀+viewname+后缀)
SpringMVC执行流程
Springmvc是spring框架的一个模块,spring和springmvc无需中间整合层整合
Springmvc是一个基于mvc的web框架
(1) .用户发送请求 至 前端控制器(DispatcherServlet);
提示:DispatcherServlet的作用:接收请求,调用其它组件处理请求,响应结果,相当于转发器、中央处理器,是整个流程控制的中心
(2) .前端控制器(DispatcherServlet)收到请求后调用处理器映射器(HandlerMapping)
(3) 处理器映射器(HandlerMapping)找到具体的Controller(可以根据xml配置、注解进行查找),并将Controller返回给DispatcherServlet;
(4) .前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)。处理器适配器经过适配调用具体的Controller;(Controller–> service --> Dao --> 数据库) ,Controller执行完成后返回ModelAndView,
提示:Model(模型数据,即Controller处理的结果,Map) View(逻辑视图名,即负责展示结果的JSP页面的名字)
(5) 处理器适配器(HandlerAdapter)将controller执行的结果(ModelAndView)返回给前端控制器(DispatcherServlet);
(6) .前端控制器(DispatcherServlet)将执行的结果(ModelAndView)传给视图解析器(ViewReslover)
(7) 视图解析器(ViewReslover)根据View(逻辑视图名)解析后返回具体JSP页面
(8) 前端控制器(DispatcherServlet)根据Model对View进行渲染(即将模型数据填充至视图中);
(9) 前端控制器(DispatcherServlet)将填充了数据的网页响应给用户。
其中整个过程中需要开发人员编写的部分有 Controller 、 Service 、 Dao 、 View;
组件说明:
Dispatcher Servlet:前端控制器
用户请求到达前端控制器,他就相当于mvc模式中的c, dispatcherServlet是整个流程控制中心,
由他调用其他组件处理用户的请求,dispatcher Servlet的存在降低了组件之间的耦合性
Handler Mapping:处理器映射器
Handler Mapping负责根据用户请求url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,
例如:配置文件方式,实现接口方式,注解方式等
Handler: 处理器
Handler是继Dispatcher Servlet前端控制器的后端控制器,在Dispatcher Servlet的控制下Handler对具体的用户请求进行处理
由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler
Handler Adapter:处理器适配器
通过Handler Adapter对处理器进行执行,这是设配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行
View Resolver:视图解析器
View Resolver负责将处理结果生成View视图,ViewResolver首先根据逻辑视图名解析成物理视图名及具体的页面地址,
在生成view视图对象,最后对view进行渲将处理结果通过页面展示给用户
View:视图
Springmvc框架提供了很多的view视图类型的支持,包括:jstlView, freemarkerview, pdfView 等。我们最常用的视图就是jsp
一般情况下需要通过页面标签或页面模板技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面
五、HashMap
1. 谈一下HashMap的特性
HashMap存储键值对实现快速存取,允许为null。Key值不可重复,若key值重复则覆盖。
非同步,线程不安全
底层是hash表,不保证有序(比如插入的顺序)
2. 谈一下HashMap的底层原理是什么?
基于hashing的原理,jdk8后采用数组+链表+红黑树的数据结构。我们通过put和get存储获取对象。当我们给put()方法传递键和值时,先对键做一个hashCode()的计算来得到它在bucket数组中的位置来存储Entry对象。当获取对象时,通过get获取得到bucket位置,在通过键对象的equals()方法找到正确的键值对,然后在返回值对象
3. 传统hashMap的缺点(为什么引入红黑树)?
Jdk1.8以前HashMap的实现是数组+链表,即使哈希函数取得再好,也很难达到元素百分百分布。当HashMap中有大量的元素都存到同一个桶中时,这个桶下有一条长长的链表,这个时候HashMap就相当于一个单链表,假如单链表有n个元素,遍历的时间复杂度就是O(n), 完全失去了它的优势。针对这种情况,jdk1.8中引入了红黑树(查找时间复杂度为O(logn))来优化这个问题
4. 请解释一下Hash Map的参数loadFactor, 它的作用是什么?
loadFactor表示HashMap的拥挤程度,影响hash操作到同一个数组位置的概率。默认loadFactor等于0.75,当Hash Map里面容纳的元素已经达到Hash Map数组长度的75%时,表示Hash Map太挤了,需要扩容,在Hash Map的构造器中可以定制loadFactor.
5. Hash Map和Hash table的区别?
线程安全 Hash Map是线程不安全的,而Hash Table是线程安全的,每个人方法通过修饰synchronized来控制线程安全
效率 Hash Map比Hash Table效率高,原因在于Hash Table的方法通过synchronized修饰后,并发的效率会降低
允不允许null HashMap运行只有一个key为null,可以有多个null的value。而HashTable不允许key, value为null
六、MySQL
1. 事务的四大特性
什么是事务
数据库事务(Database Transaction),是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
简单的说:事务就是将一堆SQL(通常是增删改操作)的执行绑在一起,要么都执行成功,要么都执行失败,即都执行成功才算成功,否则就会恢复到这堆SQL执行之前的状态。
原子性(Atomicity) :事务中所有操作是不可再分割的原子单位。事务中所有操作要么全部执行成功,要么全部执行失败。
一致性(Consistency) :事务执行后,数据库状态与其它业务规则保持一致。如转账业务,无论事务执行成功与否,参与转账的两个账号金额之和应该是不变的。
隔离性(Isolation) :隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。也就是说,在事中务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。例如:在A事务中,查看另一B事务(正在修改张三的账户金额)中张三的账户金额,要查看到B事务之前的张三的账户金额,要么查看到B事务之后张三的账户金额。
持久性(Durability) :一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。
2. 事务的并发读问题
多个事务对相同的数据同时进行操作,这叫做事务并发。
在事务并发时,如果没有采取必要的隔离措施,可能会导致各种并发问题,破坏数据的完整性等。这些问题中,其中有三类是读问题,分别是:脏读、不可重复读、幻读
脏读(dirty read):读到另一个事务的未提交更新数据,即读取到了脏数据;
例如:A给B转账100元但未提交事务,在B查询后,A做了回滚操作,那么B查询到了A未提交的数据,就称之为脏读。
不可重复读(unrepeatable read):对同一记录的两次读取不一致,因为另一事务对该记录做了修改(是针对修改操作)
例如:在事务1中,前后两次查询A账户的金额,在两次查询之间,另一事物2对A账户的金额做了修改,此种情况可能会导致事务1中,前后两次查询的结果不一致。这就是不可重复度
幻读(虚读)(phantom read):对同一张表的两次查询不一致,因为另一事务插入了一条记录(是针对插入或删除操作);
注意:mysql默认的是不允许出现脏读和不可重复读,所以在下面演示之前需要设置mysql允许出现脏读、不可重复读等。
3. 事务的隔离级别
未提交读(Read Uncommitted) :在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。
提交读(Read Committed ):这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。
可重复读(Repeated Read) :这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
串行读(Serializable) :这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
自我总结,经供参考
Java高级工程师之路