一、讲一下什么是Spring
Spring是一个轻量级的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。常见的配置方式有三种:基于XML的配置、基于注解的配置、基于Java的配置。
主要由以下几个模块组成:
Spring Core:核心类库,提供IOC服务;
Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);
Spring AOP:AOP服务;
Spring DAO:对JDBC的抽象,简化了数据访问异常的处理;
Spring ORM:对现有的ORM框架的支持;
Spring Web:提供了基本的面向Web的综合特性,例如多方文件上传;
Spring MVC:提供面向Web应用的Model-View-Controller实现
二、你们项目中为什么使用Spring框
Spring有以下特点:
- 轻量:Spring 是轻量的,基本的版本大约2MB。
- 控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。
- 面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
- 容器:Spring 包含并管理应用中对象的生命周期和配置。
- MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。
- 事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。
- 异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。
三、@Resource 和@Autowired 依赖注入的区别是什么?@Qualifier 使用场景是什么?
@Resource
只能放在属性上,表示先按照属性名匹配 IOC 容器中对象 id 给属性注入值若没有成功,会继续根据当前属性的类型匹配 IOC 容器中同类型对象来注入值若指定了 name 属性@Resource(name = "对象 id"),则只能按照对象 id 注入值。
@Autowird
-
放在属性上:表示先按照类型给属性注入值如果 IOC 容器中存在多个与属性同类型的对象,则会按照属性名注入值 也可以配合@Qualifier("IOC 容器中对象 id")注解直接按照名称注入值。
-
放在方法上:表示自动执行当前方法,如果方法有参数,会自动从 IOC 容器中寻找同类型的对象给参数传值,也可以在参数上添加@Qualifier("IOC 容器中对象 id")注解按照名称寻找对象给参数传值。
-
@Qualifier 使用场景:
@Qualifier("IOC 容器中对象 id")可以配合@Autowird 一起使用, 表示根据指定的 id 在 Spring 容器中匹配对象
四、依赖注入的方式有几种,各是什么?
一、构造器注入 将被依赖对象通过构造函数的参数注入给依赖对象,并且在初始化对象的时候注入。
优点: 对象初始化完成后便可获得可使用的对象。
缺点: 当需要注入的对象很多时,构造器参数列表将会很长; 不够灵活。若有多种注入方式,每种方式只需注入指定几个依赖,那么就需要提供多个重载的构造函数,麻烦。
二、setter方法注入 IoC Service Provider通过调用成员变量提供的setter函数将被依赖对象注入给依赖类。
优点: 灵活。可以选择性地注入需要的对象。
缺点: 依赖对象初始化完成后由于尚未注入被依赖对象,因此还不能使用。
三、接口注入 依赖类必须要实现指定的接口,然后实现该接口中的一个函数,该函数就是用于依赖注入。该函数的参数就是要注入的对象。
优点 接口注入中,接口的名字、函数的名字都不重要,只要保证函数的参数是要注入的对象类型即可。
缺点: 侵入行太强,不建议使用。
PS:什么是侵入行? 如果类A要使用别人提供的一个功能,若为了使用这功能,需要在自己的类中 增加额外的代码,这就是侵入性
五、Spring的两大核心是什么?谈一谈你对IOC的理解? 谈一谈你对DI的理解?谈一谈你对 AOP 的理解?(必会)
-
Spring 的两大核心是:IOC(控制翻转)和 AOP(面向切面编程) DI(依赖注入)
-
IOC 的意思是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到 Spring 容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。最直观的表达就是,IOC 让对象的创建不用去 new 了,可以由 spring 根据我们提供的配置文件自动生产,我们需要对象的时候,直接从 Spring 容器中获取即可. Spring 的配置文件中配置了类的字节码位置及信息, 容器生成的时候加载配置文件识别字节码信息, 通过反射创建类的对象.。
Spring 的 IOC 有三种注入方式 :构造器注入, setter 方法注入, 根据注解注入。
-
DI 的意思是依赖注入,和控制反转是同一个概念的不同角度的描述,即应用程序在运行时依赖 Io c 容器来动态注入对象需要的外部资源。
-
AOP,一般称为面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect). SpringAOP 使用的动态代理,所谓的动态代理就是说 AOP 框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个 AOP 对象,这个 AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
-
Spring AOP 中的动态代理主要有两种方式,JDK 动态代理和 CGLIB 动态代理:
(1)JDK 动态代理只提供接口代理,不支持类代理,核心 InvocationHandler 接口和Proxy 类,InvocationHandler 通过 invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起,Proxy 利用 InvocationHandler 动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
(2) 如果代理类没有实现 InvocationHandler 接口,那么 Spring AOP 会选择使用CGLIB 来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现 AOP。CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final,那么它是无法使用 CGLIB 做动态代理的。
六、什么是通知呢?有哪些类型呢?
通知是个在方法执行前或执行后要做的动作,实际上是程序执行时要通过SpringAOP框架触发的代 码段。 Spring切面可以应用五种类型的通知:
- 前置通知 before:前置通知,在一个方法执行前被调用。
- 最终通知 after: 在方法执行之后调用的通知,无论方法执行是否成功。
- 后置通知 after-returning: 仅当方法成功完成后执行的通知。
- 异常通知 after-throwing: 在方法抛出异常退出时执行的通知。
- 环绕通知 around: 在方法执行之前和之后调用的通知。
七、Spring 支持 bean 的作用域有几种吗? 每种作用域是什么样的?(必会)
Spring 支持如下 5 种作用域:
(1)singleton:默认作用域,单例 bean,每个容器中只有一个 bean 的实例。
(2)prototype:为每一个 bean 请求创建一个实例。
(3)request:为每一个 request 请求创建一个实例,在请求完成以后,bean 会失效并被垃圾回收器回收。
(4)session:与 request 范围类似,同一个 session 会话共享一个实例,不同会话使用不同的实例。
(5)global-session:全局作用域,所有会话共享一个实例。如果想要声明让所有会 话共享的存储变量的话,那么这全局变量需要存储在 global-session 中。
八、Spring 框架中都用到了哪些设计模式?(必会)
- 工厂模式:BeanFactory 就是简单工厂模式的体现,用来创建对象的实例
- 单例模式:Bean 默认为单例模式
- 代理模式:Spring 的 AOP 功能用到了 JDK 的动态代理和 CGLIB 字节码生成技术
- 模板方法 :用来解决代码重 复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate
- 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所 有 依 赖 于 它 的 对 象 都 会 得 到 通 知 被 制 动 更 新 , 如 Spring 中 listener 的 实 现--ApplicationListener
九、Spring 事务的实现方式和实现原理(必会)
Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring 是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过 binlog 或者 redo log 实现的。
spring 事务实现主要有两种方法:
- 编程式,beginTransaction()、commit()、rollback()等事务管理相关的方法
- 声明式,利用注解 Transactional 或者 aop 配置
十、Spring 的对象默认是单例的还是多例的? 单例 bean 存不存在线程安全问题呢?(必会)
-
在 spring 中的对象默认是单例的,但是也可以配置为多例。
-
单例 bean 对象对应的类存在可变的成员变量并且其中存在改变这个变量的线程时,多线程操作该 bean 对象时会出现线程安全问题。
原因是:多线程操作如果改变成员变量,其他线程无法访问该 bean 对象,造成数据混乱。
解决办法:在 bean 对象中避免定义可变成员变量;在 bean 对象中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中
十一、Spring 的事务传播行为
spring 事务的传播行为说的是,当多个事务同时存在的时候,spring 如何处理这些事务的行为。
备注(方便记忆): propagation 传播
require 必须的/suppor 支持/mandatory 强制托管/requires-new 需要新建/not -supported 不支持/never 从不/nested 嵌套的
① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
④ PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
⑦ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按 REQUIRED 属性执行
十二、Spring 中的隔离级别
ISOLATION 隔离的意思
① ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。
② ISOLATION_READ_UNCOMMITTED:读未提交,允许另外一个事务可以看到这个事务未提交的数据。
③ ISOLATION_READ_COMMITTED:读已提交,保证一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有记录的更新。解决脏读问题
④ ISOLATION_REPEATABLE_READ:可重复读,保证一个事务修改的数据提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新。行锁
⑤ ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新。表锁