spring相关面试题(全干货)

谈谈你对spring的理解:

Spring 是一个开源框架,可以实现java模块化开发,贯穿表现层,业务层,逻辑层,实现了各个层之间的解耦合关系
Spring 有两大核心是:IOC(控制反转)和 AOP(面向切面编程)    DI(依赖注入)

(1)IOC(控制反转的理解):就是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到 Spring 容器中,并由容器根据配置文件去创 建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。

IOC 让对象的创建不用去 new 了,可以由 spring 根据我们提供的配置文 件自动生产,我们需要对象的时候,直接从 Spring 容器中获取即可.
Spring 的配置文件中配置了类的字节码位置及信息, 容器生成的时候加载配置文件识 别字节码信息, 通过反射创建类的对象.
Spring 的 IOC 有三种注入方式 :构造器注入, setter 方法注入, 根据注解注入。
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 做动态代理的
扩展:
DI依赖注入:
当一个被Spring管理的对象,存在另一个对象(依赖于另一个对象)时,就需要使用依赖注入,来完成对象之间的 依赖关系
依赖注入是指在 Spring IOC 容器创建对象的过程中,将所依赖的对象通过配置进行注入。我们可以通过依赖注入的方式来降低对象间的耦合度。
借阅一下大神讲解

spring中bean的生命周期:

1 准备Spring的上下文环境,也就是ApplicationContext(Spring中的核心接口和容器,允许容器通过应用程序上下文环境创建、获取、管理bean)

2 扫描XML文件,或者是注解,得到一系列的BeanDefinitaion

3 然后通过BeanFactoryPostProcessor(Bean工厂的后置处理器), 要对BeanDefinition做一些处理,替换一些属性的值,比如MyBatis的Bean,就会做这个处理。

4 开始实例化Bean,即new出来Java对象,当然,他不是真的new,而是通过反射实例化Bean

5 开始初始化Bean,对Bean的属性赋值,即根据Bean的依赖关键,进行Bean的依赖注入

6 对Bean的后置处理,调用BeanPostProcessor,进行AOP相关的操作,这时候就会对Bean进行切面增强。

7 将Bean放入Bean容器,即一个HashMap中,这时候开发者就可以使用这个Bean了。

8 Bean的销毁,当Spring的AppliationContext要关闭的时候,会调用DisposableBean的destory方法,或者Bean的destory方法,进行Bean销毁。

 BeanFactory 和 ApplicationContext 有什么区别

BeanFactory:
Spring 最顶层的接口,实现了 Spring 容器的最基础的一些功能, 调用起来比较麻 烦, 一般面向 Spring 自身使用
BeanFactory 在启动的时候不会去实例化 Bean,从容器中拿 Bean 的时候才会去
实例化
ApplicationContext:
ApplicationContext继承了BeanFactory, 扩展了其功能,所以ApplicationContext拥有BeanFactory所有的特点,也是⼀个Bean⼯⼚, 一般面向程序员身使用
ApplicationContext 在启动的时候就把所有的 Bean 全部实例化了
ApplicationContext 还继承了EnvironmentCapable、MessageSource、ApplicationEventPublisher等接⼝,从⽽ ApplicationContext还有获取系统环境变量、国际化、事件发布等功能,这是BeanFactory所不具备的
补充:{

ApplicationContext
1.ApplicationContext是一个接口,提供了访问spring容器的API

2.ClassPathXmlApplicationContext是一个类,实现了上述功能

3.ApplicationContext的顶层接口是BeanFactory

4.BeanFactory定义了bean相关的最基本操作

5.ApplicationContext在BeanFactory基础上追加了若干新功能

}

单例Bean和单例模式

单例模式表示JVM中某个类的对象只会存在唯⼀⼀个。

⽽单例Bean并不表示JVM中只能存在唯⼀的某个类的Bean对象。

spring的bean是线程安全的吗?

Spring容器 本身并没有提供Bean的线程安全策略,所以可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体情况还是要结合Bean的作用域来讨论。

Bean的作用域

singleton:默认作用域,单例bean,每个容器中只有一个bean的实例。
prototype:为每一个bean请求创建一个实例。
request:为每一个request请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
session:与request范围类似,同一个session会话共享一个实例,不同会话使用不同的实例。
application:bean定义在servletContext的生命周期中复用一个单例对象(跨容器)。
global-session:全局作用域,所有会话共享一个实例。如果想要声明让所有会话共享的存储变量的话,那么这全局变量需要存储在global-session中。
Bean的线程安全分析

对于prototype作用域的Bean,每次都创建一个新对象,也就是线程之间不存在Bean共享,因此不会有线程安全问题。
对于singleton作用域的Bean,所有的线程都共享一个单例实例的Bean,因此是存在线程安全问题的。
但是如果单例Bean是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。解释一下:

无状态Bean(Stateless Bean):就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。
有状态Bean(Stateful Bean) :就是有实例变量的对象,可以保存数据,是非线程安全的。
对于有状态的bean(比如Model和View),就需要自行保证线程安全, 解决办法就是:

将有状态的bean的作用域由“singleton”改为“prototype”

{

singleton和prototype的区别:

singleton是单实例,prototype是多实例

前者在加载spring配置文件时候就会创建单实例对象

后者不是在加载spring配置文件时候创建对象,在调用getBean方法时候创建多实例对象

}
采用ThreadLocal解决线程安全问题,为每个线程提供一个独立的变量副本
线程同步机制和ThreadLocal都是为了解决多线程中相同变量的访问冲突问题:

同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。
ThreadLocal采用了“空间换时间”的方式。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。
 

Spring 的对象默认是单例的还是多例的? 单例 bean 存不存在线程安全问

题呢?

1. 在 spring 中的对象默认是单例的,但是也可以配置为多例。在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例
2. 单例 bean 对象对应的类存在可变的成员变量并且其中存在改变这个变量的线程时,
多线程操作该 bean 对象时会出现线程安全问题。
原因是:多线程操作如果改变成员变量,其他线程无法访问该 bean 对象,造成数据混
乱。
解决办法:在 bean 对象中避免定义可变成员变量;
在 bean 对象中定义一个 ThreadLocal 成员变量,将需要的可变成员变量
保存在 ThreadLocal 中。

Spring 框架中都用到了哪些设计模式?

1. 工厂模式:BeanFactory 就是简单工厂模式的体现,用来创建对象的实例
2. 单例模式:Bean 默认为单例模式
3. 代理模式:Spring 的 AOP 功能用到了 JDK 的动态代理和 CGLIB 字节码生成技术
4. 模板方法 :用来解决代码重 复的问题。比如. RestTemplate, JmsTemplate,
JpaTemplate
5. 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,
所 有 依 赖 于 它 的 对 象 都 会 得 到 通 知 被 制 动 更 新 , 如 Spring 中 listener 的 实 现
--ApplicationListener

Spring 事务的实现方式和实现原理

Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring 是
无法提供事务功能的。真正的数据库层的事务提交和回滚是通过 binlog 或者 redo log 实
现的。
spring 事务实现主要有两种方法
1、编程式,beginTransaction()、commit()、rollback()等事务管理相关的方法
2、声明式,利用注解 Transactional 或者 aop 配置

Spring的常用注解

@Component 标识为普通组件

​ @Service 标识为业务层组件

​ @Controller 标识为控制层组件

​ @Repository 标识为持久层组件

*上面四个注解功能是一样的,都可以用来创建bean实例

属性注入:

​ @AutoWired:根据属性类型进行自动注入(装配)

​ @Qualifier:根据名称进行注入(这个Qualifier注解的使用,要和上面@Autowired一起使用)

​ @Resource:可以根据类型注入,也可以根据名称注入

​ @Value:注入普通类型属性

配置类:

​ @Configuration 标识这个类是一个配置类

​ @ComponentScan 开启组件扫描

​ @EnableTransactionManagement 开启事务

​ @Bean 创建bean实例

​ @Transactional 一般是在业务逻辑层加的 让该类有事务的功能特性

​ @RequestMapping 将请求和处理请求的控制器方法关联起来,建立映射关系

​ @PathVariable 将占位符所表示的数据赋值给控制器方法的形参 (用于RESTful风格中)

​ @ResponseBody 将该方法的返回值直接作为响应报文的响应体响应到浏览器,当成是一个响应体返回数据而不是视图名称

​ @RestController 复合注解,标识在控制器的类上,@RestController=@Controller+@ResponseBody

@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 容器中匹配对象

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事务什么时候会失效

spring事务的原理是AOP,进⾏了切⾯增强,那么失效的根本原因是这个AOP不起作⽤了!常⻅情况有 如下⼏种

1、发⽣⾃调⽤,类⾥⾯使⽤this调⽤本类的⽅法(this通常省略),此时这个this对象不是代理类,⽽是 UserService对象本身! 解决⽅法很简单,让那个this变成UserService的代理类即可!

2、⽅法不是public的:@Transactional 只能⽤于 public 的⽅法上,否则事务不会失效,如果要⽤在 ⾮ public ⽅法上,可以开启 AspectJ 代理模式。

3、数据库不⽀持事务

4、没有被spring管理

5、异常被吃掉,事务不会回滚(或者抛出的异常没有被定义,默认为RuntimeException)

Spring中什么时候@Transactional会失效

因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有是被代理对象调⽤时, 那么这个注解才会⽣效,所以如果不是被代理对象来调⽤这个⽅法,那么@Transactional是不会生效的。

同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是基于⽗⼦类来实现的,⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的利⽤代理,也会导致@Transactianal失效

Spring 中的隔离级别

ISOLATION 隔离的意思
① ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,
使用数据库默认的事务隔离级别。
② ISOLATION_READ_UNCOMMITTED:读未提交,允许另外一个事务可以看到这个
事务未提交的数据。
③ ISOLATION_READ_COMMITTED:读已提交,保证一个事务修改的数据提交后才
能被另一事务读取,而且能看到该事务对已有记录的更新。解决脏读问题
④ ISOLATION_REPEATABLE_READ:可重复读,保证一个事务修改的数据提交后才
能被另一事务读取,但是不能看到该事务对已有记录的更新。行锁
⑤ ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据
库所做的更新。表锁
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xainbro

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值