本文中的面试题主要是本人觉得重要或者曾经在面试中遇到过的题目。
1. 谈谈你对spring的IOC和DI的理解,他们有什么区别?
IOC即控制反转,就是将原本手动在程序中创建java对象的控制权交给spring框架管理。
DI即依赖注入,在spring负责创建Bean对象是,动态的将依赖对象注入到bean组件。
IOC和DI吧应用代码量降低,以最小代价和最小的侵入性使松散耦合得以实现。
IOC和DI的区别:IOC控制反转指将对象的创建权反转到spring容器,而DI依赖注入指spring创建对象的过程中,将对象依赖属性通过配置进行注入。
2. BeanFactory和ApplicationContext接口有什么区别?
- ApplicationContext接口继承自BeanFactory接口,spring的核心工厂是BeanFactory,BeanFactory采取延迟加载,第一次getBean时才会初始化Bean,而ApplicationContext是会在加载配置文件的时候初始化Bean。
- ApplicationContext是对BeanFactory扩展,它可以进行国际化处理、事件传递和bean自动装配以及各种不同应用层的Context实现。开发中基本都在使用ApplicationContext,web项目中使用WebApplicationContext,很少用到BeanFactory。
3. spring配置Bean实例化有哪些方式?
- 使用类构造器实例化(默认无参数)
- 使用静态工厂方法实例化(简单工厂模式)
- 使用实例工厂方法实例化(工厂方法模式)
4. 说下spring中Bean的生命周期
① 对象实例化
② 为Bean的属性设置值和对其他Bean进行引用
③ 将Bean实例传递给Bean后置处理器的postProcessBeforeInitialization方法
④ 调用Bean的初始化方法
⑤ 将Bean实例传递给Bean后置处理器的postProcessAfterInitialization方法
⑥ 执行业务处理
⑦ 容器关闭时,调用Bean的销毁方法(destroy-method)
5. Bean的作用域
- single
IOC容器中只会存在一个共享的Bean实例,并且所有对Bean的请求,只要id与该Bean定义相匹配,则只会返回Bean的同一实例 - prototype
每次对该Bean请求时都会创建一个虚拟的实例。 对所有有撞状态的Bean用该作用域 - request
在一次HTTP请求中,一个Bean定义对应一个实例;每次HTTP请求都会有各自的实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。 - session
在一次HTTP Session中,一个Bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。 - global session
在一次HTTP Session中,一个Bean定义对应一个实例;典型情况下仅在porlet context的时候有效,。该作用域仅在基于web的Spring ApplicationContext情形下有效。
6. Bean有哪些注入方式?
- 实现Injection接口注入
- 构造器注入
- setter注入(常用)
7. 什么是AOP,AOP的作用是什么?
AOP(面向切面编程)提供了另一种思考程序的角度,弥补了OOP(面向对象编程)的不足。
除了类(classes)以外,AOP提供了切面。切面对关注点进行模块化,例如横切多个类型和对象的事务管理
Spring的一个关键的组件就是AOP框架,可以自由选择是否使用AOP
提供声明式企业服务,特别是为了替代EJB声明式服务。最重要的服务是声明性事务管理,这个服务建立在Spring的抽象事物管理之上
允许用户实现自定义切面,用AOP来完善OOP的使用
可以把Spring AOP看作是对Spring的一种增强
8. 说说AOP的优点和应用场景
- AOP的优点:
1-降低模块之间的耦合度。
2-使系统容易扩展。
3-更好的代码复用。 - AOP的应用场景:
1.日志处理
2.用户登录
3.权限(Authentication )
4.性能优化(Performance optimization)
5.事务(Transactions )
6.记录跟踪 优化 校准(logging, tracing, profiling and monitoring)
7.调试(Debugging)
8.懒加载(Lazy loading)
9.错误处理(Error handling)
10.资源池(Resource pooling)
11.同步(Synchronization)
8. spring支持的事务管理类型有哪些?
- 声明式事务:可以将业务代码和事务管理分离,只需要通过注解和xml配置来管理事务。
- 编程性事务: 特别灵活但是难以维护。
9.spring事务支持的隔离级别
spring支持4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。
- ISOLATION_READ_UNCOMMITED对应数据库的Read Uncommitted(读取未提交内容)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。 - ISOLATION_READ_COMMITED对应数据库的Read Committed(读取提交内容)
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。 - ISOLATION_REPEATABLE_READ对应数据库的Repeatable Read(可重读)
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。 - ISOLATION_SERIALIZABLE对应数据库的Serializable(可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。例如:
脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。
在MySQL中,实现了这四种隔离级别,分别有可能产生问题如下所示: - ISOLATION_DEFALUT使用数据库的默认隔离级别
数据库隔离级别 | spring隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|---|
Read uncommitted | ISOLATION_READ_UNCOMMITED | Yes | Yes | Yes |
Read committed | ISOLATION_READ_COMMITED | No | Yes | Yes |
Repeatable read | ISOLATION_REPEATABLE_READ | No | No | Yes |
Serializable | ISOLATION_SERIALIZABLE | No | No | No |
默认 | ISOLATION_DEFALUT |
10.spring事务的传播行为
- @Transactional(propagation=Propagation.REQUIRED)
如果有事务, 那么加入事务, 没有的话新建一个(默认情况下) - @Transactional(propagation=Propagation.NOT_SUPPORTED)
容器不为这个方法开启事务 - @Transactional(propagation=Propagation.REQUIRES_NEW)
不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务 - @Transactional(propagation=Propagation.MANDATORY)
必须在一个已有的事务中执行,否则抛出异常 - @Transactional(propagation=Propagation.NEVER)
必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反) - @Transactional(propagation=Propagation.SUPPORTS)
如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务. - @Transactional(propagation=Propagation.NESTED)
嵌套事务。该级别的特点是,如果 Context 中存在事务 A,就将当前代码对应的事务 B 加入到 事务 A 内部,嵌套执行;如果 Context 中不存在事务,则新建事务执行代码。换句话说,事务 A 与事务 B 之间是父子关系,A 是父,B 是子。理解嵌套事务的关键点是:save point。
父、子事务嵌套、save point 的说明:
1 父事务会在子事务进入之前创建一个 save point;
2 子事务 rollback ,父事务只会回滚到 save point,而不会回滚整个父事务;
3 父事务 commit 之前,必须先 commit 子事务