#1.谈谈你对 Spring 的理解?

1.狭义上 spirng 就是指 Spring Framework,特别是其中的核心思想控制反转和依赖注入、事务处理等特性,在进行大型项目开发的时候能够帮助我们更好的管理对象。
2.广义上 spring 就是指 spring 家族的一些列产品:如 SpringMvc,SpringBoot,SpringJPA,SpringCloud 等等。Spring 是项目开发中最重要的框架,可以帮助我们更好的管理对象,减少依赖,提高开发效率。

#2.Spring中的容器是什么?

容器是Spring的核心,用来存放、初始化、管理Bean对象的(通过IOC管理)、相当于生产Bean的工厂。在xml中进行配置。

#3.Spring框架中的单例bean是线程安全的吗?它是如何处理线程并发问题的?

不是,Spring框架中的单例bean不是线程安全的。
spring 中的 bean 默认是单例模式,spring 框架并没有对单例 bean 进行多线程的封装处理。实际上大部分 spring bean 是无状态的(比如 dao 类),在某种程度上来说 bean 也是安全的,但如果 bean 有状态的话(比如 view model )就要开发者自己去保证线程安全了,最简单的就是改变 bean 的作用域,把“singleton”变更为“prototype”,这样请求 bean 相当于 new Bean()了, 保证线程安全了。

有状态就是有数据存储功能。
无状态就是不会保存数据。

#3.1.Spring如何处理线程并发问题?

一般只有无状态的Bean才可以在多线程下共享,大部分是无状态的Bean。当存有状态的Bean的时候,spring一般是使用ThreadLocal进行处理,解决线程安全问题。

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。
同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。
ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,所以没有相同变量的访问冲突问题。所以在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。

#4.Spring中的IOC是指什么?

IOC (Inversion of Control)即控制反转(把对象的控制权从程序代码本身转移外部的容器中),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。

为什么有IOC? 为了解决对象之间的耦合度过高的问题。

#4.1.谁控制谁,控制什么:

传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IOC是有专门一个容器来创建这些对象,即由IOc容器来控制对象的创建而不再显式地使用new;

谁控制谁?当然是IOC容器控制了对象;

控制什么?那就是主要控制了外部资源获取和生命周期(不只是对象也包括文件等)。

为何是反转,哪些方面反转了:
有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;

哪些方面反转了?依赖对象的获取被反转了。

#5.说说Spring中的IOC和DI的关系?

IOC“控制反转” 不是什么技术,而是一种设计思想。
DI是“依赖注入”是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。
DI其实就是IOC的另外一种说法,DI是由Martin Fowler 在2004年初的一篇论文中首次提出的。他总结道:控制的什么被反转了?就是获得依赖对象的方式反转了。

谁依赖于谁:当然是应用程序依赖于IOC容器;
为什么需要依赖:应用程序需要IOC容器来提供对象需要的外部资源;
谁注入谁:很明显是IOC容器注入应用程序某个对象,应用程序依赖的对象;
注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。

什么时候进行依赖注入?

在beandefinition 实例化bean的时候,还未初始化属性 这个时候就调用DI 通过set 或者 构造方式的注入。

#6.依赖注入四种方式?

a、接口注入;(其中接口注入由于在灵活性和易用性比较差,现在从Spring4开始已被废弃。)
b、setter方法注入;
c、构造方法注入;
d、注解方法注入;

#7.Spring中bean的五种自动装配方式?

Spring 装配包括手动装配和自动装配,手动装配是有基于 xml 装配、构造方法、setter 方法等自动装配有五种自动装配的方式,可以用来指导 Spring 容器用自动装配方式来进行依赖注入。

五种:

  1. no:默认的方式是不进行自动装配,通过显式设置 ref 属性来进行装配。
  2. byName:通过参数名 自动装配,Spring 容器在配置文件中发现 bean 的 autowire 属性被设 置成 byname,之后容器试图匹配、装配和该 bean 的属性具有相同名字的 bean。
  3. byType:通过参数类型自动装配,Spring 容器在配置文件中发现 bean 的 autowire 属性被 设置成 byType,之后容器试图匹配、装配和该 bean 的属性具有相同类型的 bean。如果有多 个 bean 符合条件,则抛出错误。
  4. constructor:这个方式类似于 byType, 但是要提供给构造器参数,如果没有确定的带参数 的构造器参数类型,将会抛出异常。
  5. autodetect:首先尝试使用 constructor 来自动装配,如果无法工作,则使用 byType 方式。

#8.Spring IOC 的过程原理?

1、读取Bean配置信息。(通过xml或者注解(全部的注解都可以)的方式)
2、根据Bean注册表实例化Bean
3、将Bean实例放到Spring容器中
4、使用Bean

Spring 一个请求是一个线程吗 spring是单线程还是多线程_AOP

#9.Spirng中AOP的概念?AOP是什么?

AOP又叫面向切面编程,是面向对象编程 OOP 的一种补充。
面向对象编程是从静态角度考虑程序的结构,而面向切面编程是从动态角度考虑程序运行过程。
在面向切面编程AOP的思想里面,核心业务功能和切面功能(事务处理、日志管理、权限控制等)分别独立进行开发,然后把切面功能和核心业务功能 “编织” 在一起,这就叫AOP。

#10.AOP两种代理方式以及区别?

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。
JDK 动态代理只能对实现了接口的类生成代理,而不能针对类.
JDK 动态代理主要涉及到 java.lang.reflect 包中的两个类:Proxy 和 InvocationHandler。
InvocationHandler 是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类 的代码,动态将横切逻辑和业务逻辑编制在一起。
Proxy 利用 InvocationHandler 动态创建 一个符合某一接口的实例,生成目标类的代理对象。

CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)CGLib 全称为 CodeGeneration Library,是一个强大的高性能,高质量的代码生成类库, 可以在运行期扩展Java 类与实现 Java 接口,CGLib 封装了 asm,可以再运行期动态生成新class。

CGLIB和 JDK 动态代理相比较:

JDK 创建代理有一个限制,就是只能为接口创建代理实例, 而对于没有通过接口定义业务方法的类,则可以通过CGLib 创建动态代理。(一个是只能在接口内,另一个在类内)

Spring 在选择用 JDK 还是 CGLiB 的依据:
(1)当 Bean 实现接口时,Spring 就会用 JDK 的动态代理
(2)当 Bean 没有实现接口时,Spring 使用 CGlib 是实现
(3)可以强制使用 CGlib(在 spring 配置中加入<aop:aspectj-autoproxy proxy-target-class=“true”/>

CGlib 比 比 JDK 快??
(1)使用 CGLib 实现动态代理,CGLib 底层采用 ASM 字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib 不能对声明为 final 的方法进行代理,因为 CGLib 原理是动态生成被代理类的子类。
(2)在对 JDK 动态代理与 CGlib 动态代理的代码实验中看,1W 次执行下,JDK7 及 8 的动态代理性能比 CGlib 要好 20%左右。

#11.AOP中Spring通知有哪些类型?

Spring切面可以应用5种类型的通知:

  1. 前置通知(Before):在目标方法被调用之前调用通知功能;
  2. 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
  3. 返回通知(After-returning ):在目标方法成功执行之后调用通知;
  4. 异常通知(After-throwing):在目标方法抛出异常后调用通知;
  5. 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为

#12.AOP实现方式?

1、静态AOP:在编译期,切面直接以字节 码的形式编译到目标字节 码文件中。
2、动态AOP(JDK动态代理):在运行期,目标类加载后,为接口动态生成代理类,将切面植入到代理类中。
3、动态代码字节生成(cglib):在运行期,目标类加载后,动态构建字节码文件生成目标类的子类,将切面逻辑加入到子类中。
4、自定义类加载器:在运行前,目标加载前,将切面逻辑加到目标字节码中。

#13.Spring的事务管理ACID特性?

原子性(Atomicity),一致性(Consistency),隔离性(lsolation),持久性(Durability)。
atomic( 原子性 ): 要么都发生,要么都不发生。
consistent( 一致性 ): 数据应该不被破坏。修改前与修改后都可以看到,修改中间不可以看到
Isolate( 隔离性 ): 用户间操作不相混淆
Durable( 持久性 ): 永久保存 , 例如保存到数据库中等

#14.Spring如何管理事务(四种方式)?

(1)编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
(2)基于 TransactionProxyFactoryBean的声明式事务管理
(3)基于 @Transactional 的声明式事务管理
(4)基于Aspectj AOP配置事务

#15.spring五个事务隔离级别是什么?

这些常量均是以 ISOLATION_开头。即形如 ISOLATION_XXX。

DEFAULT:采用 DB 默认的事务隔离级别。
MySql 的默认为 REPEATABLE_READ(可重复读);Oracle默认为 READ_COMMITTED。(读已提交)
READ_UNCOMMITTED:读未提交。未解决任何并发问题。
READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
SERIALIZABLE:串行化。不存在并发问题。

#16.spirng中七个事务传播行为是什么?

① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务就加入该事务,该设置是最常用的设置。
② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
④ PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
⑦ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行

#17.spring中不同的隔离级别有不同的数据一致性问题?

脏读 :表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录 A,此时该事务还未提交,然后另一个事务尝试读取到了还未提交的数据A。
不可重复读 :是指在一个事务内,多次读同一数据。
幻读 :指同一个事务内多次查询返回的结果集不一样。比如同一个事务 A 第一次查询时候有 n 条记录,但是第二次同等条件下查询却有 n+1 条记录,产生了幻觉。发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,所有数据行的者变少了。

#18.Spring 中体现的设计模式?

工厂设计模式 : Spring 使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。
代理设计模式 : Spring AOP 功能的实现。
单例设计模式 : Spring 中的 Bean 默认都是单例的。
模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。

#19.SpringMVC 的实现原理?

用户发送请求至前端控制器-调用处理器映射器-生成处理器对象-返回前端控制器-处理适配器-调用具体的处理器Controller返回一个ModelAndView给前端控制器-调用视图解析器-视图渲染-响应用户.

1、用户发送请求至前端控制器 DispatcherServlet。
2、 DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器。
3、处理器映射器找到具体的处理器(可以根据 xml 配置、注解进行查找),生成处理器
对象及处理器拦截器(如果有则生成)一并返回给 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 响应用户。

#20.SpringMVC有那些组件?

前端控制器DispatcherServlet
处理器映射器HandlerMapping
处理器适配器HandlerAdapter
处理器Handler(需要工程师开发)
视图解析器View resolver
视图View