Spring核心问题回顾3:spring的事务传播机制、事务失效的情况、对ioc的理解
1、spring是如何简化开发的?spring的优势有哪些?
Spring是一个框架,同时是一个容器,还是一个生态
。
IOC是一种理论思想,DI是具体的实现方式
。
1)Spring通过DI, AOP和消除样板式代码来简化企业级java开发
2)Spring框架之外,还存在一个构建在核心框架之上的庞大生态圈,它将Spring扩展到不同的领域,比如web服务器、REST、移动开发、以及Nosql
3)低侵入式涉及,代码的污染极低
4)独立于各种应用服务器,基于Spring框架的应用,可以真正实现Write Once, Run Anywhere
5)Spring的ioc容器降低了业务对象替换的复杂性,提高了组件之间的解耦
6)Spring的AOP支持允许将一些通用任务如安全、事务、日志等进行集中式处理,从而提供了更好的复用
7)Spring的ORM和DAO提供了与第三方持久层框架的良好整合,并简化了底层的数据库访问
8)Spring的高度开放性,并不强制应用完全依赖于Spring,开发者可自由选用Spring框架的部分或者全部
2、spring的事务传播机制是什么?
spring有7种事务传播机制:
REQUIRED
:默认的传播特性,如果当前没有事务,则新建一个事务;如果当前存在事务,则加入这个事务- SUPPORTS:当前存在事务,则加入当前事务;如果当前没有事务,则以非事务的方式执行
- MANDATORY:当前存在事务,则加入当前事务;如果当前事务不存在,则抛出异常
REQUIRED_NEW
:创建一个新事务,如果存在当前事务,则挂起该事务- NOT_SUPPORTED:以非事务方式执行,如果存在当前事务,则挂起当前事务
- NEVER:不使用事务,如果当前事务存在,则抛出异常
NESTED
:如果当前事务存在,则在嵌套事务中执行;如果当前不存在事务,则创建新事务
REQUIRED, REQUIRES_NEW, NESTED对比:
REQUIRED(spring默认级别)
:外部和内部方法,任何一个方法异常,都会全部回滚
1)内部抛异常:
外部如果没有catch,这个异常会向上抛,外部会回滚。
外部如果catch了,spring事务管理器会替外部方法向上抛一个UnexpectedRollbackException方法。
因此无论是否catch,只要内部异常,外部就一定会回滚。
2)外部抛异常:内部回滚
REQUIRES_NEW
:外部异常,内部不回滚;内部异常,根据外部是否catch来决定是否回滚
1)内部抛异常:
外部如果catch住了,外部不回滚
外部如果没有catch住,外部回滚
2)外部抛异常:内部不回滚
NESTED
:外部异常,内部回滚;内部异常,根据外部是否catch来决定是否回滚
内外方法是嵌套事务。原理是内部事务会在外部事务中创建一个savepoint,内部事务异常后会回滚到这个savepoint点。
1)内部抛异常:
外部如果catch住了,外部不回滚
外部如果没有catch住,外部回滚
2)外部抛异常:内部回滚
3、spring事务实现方式的原理是什么?
在使用spring框架时,可以有2种事务的实现方式。一种是编程式事务
,由用户通过代码来控制事务的处理逻辑;另一种是声明式事务
,通过@Transactional注解来实现。
其实事务的操作贝莱应该是由数据库来进行控制的,但是为了方便用户进行业务逻辑的操作,spring对事务功能进行了扩展实现。一般很少会用编程式事务,更多的是通过添加@Transactional注解来进行实现,当添加此注解后,事务的自动提交功能就会关闭,由spring框架来进行控制。
事务操作是AOP的一个核心体现,当一个方法添加@Transactional注解后,spring会基于这个类生成一个代理对象,会将这个代理对象作为bean。当使用这个代理对象的方法时,如果有事务处理,会先把自动提交关闭,然后执行具体的业务逻辑。如果业务逻辑没有任务异常,那么代理逻辑就会直接提交,如果出现任何异常,就进行回滚操作。
4、spring事务什么时候会失效?
未被spring管理
:使用Spring事务的前提是,对象要被Spring管理,事务方法所在的类要被加载为bean对象数据库不支持事务
:以MySQL为例,InnoDB引擎是支持事务的,而像MyISAM、MEMORY等是不支持事务的事务方法没有被public修饰
:java的访问权限修饰符有4种,private、default、protected、public四种,但是@Transactional注解只能作用于public修饰的方法上使用final修饰了方法
:如果事务方法使用final修饰,那么aop就无法在代理类中重写该方法,事务就不会生效。同样的,static修饰的方法也无法通过代理变成事务方法。同一个类中方法调用
:同一个类中的方法没有事务,在该方法中调用一个有事务的方法,那么该事务也无效。因为调用的是类本身的方法,而不是代理对象的方法。多线程调用
:因为两个操作不在一个线程中,获取到的数据库连接不一样,从而是两个不同的事务,所以也不会回滚。错误的传播行为
:Spring定义了7种传播行为,我们可以通propagation属性来指定传播行为参数,目前只有REQUIRED、REQUIRES_NEW、NESTED会创建新的事务,其他的则会以非事务的方式运行或者抛出异常自己try...catch...掉了异常
:如果没有异常抛出,则Spring认为程序是正常的,就不会回滚手动抛出了错误的异常
:Spring默认只会回滚RuntimeException和Error对于普通的Exception,不会回滚。如果你想触发其他异常的回滚,需要在注解上配置一下,如:@Transactional(rollbackFor = Exception.class)
10.嵌套事务回滚多了
:即内层事务出现异常,因为没有try,catch住,导致外层事务页进行了回滚。
5、spring支持的bean的作用域有哪些?
- singleton:默认的作用域,单例Bean,每个Spring IOC容器中只有一个bean的实例
- prototype:原型模式,每次用getBean方法获取prototype定义的bean的时候,都会产生一个新的Bean的实例;
- request:为每一个request请求创建一个bean的实例,在这个请求完成之后,这个bean就会失效,然后被Spring的垃圾回收站回收;
- session:与request的范围基本相似,同一个session会话共享一个bean的实例,不同session会话之间使用的是不同的bean的实例,只有在Web应用中使用Spring的时候,该作用域才会有效;
- global-session:全局作用域,所有的会话共享同一个bean实例,所以说,如果我们想要声明一个让所有会话共享的存储变量的时候,那这个全局变量就应该存储在global-session中。
6、谈谈对spring ioc的理解,原理和实现?
总:
ioc是一个理论思想,DI是具体实现。
原来的对象是由使用者来进行控制,有了spring ioc之后,可以把整个对象交给spring来帮我们进行管理
DI:依赖注入,把对应的属性的值注入到具体的对象中,@Autowired, populateBean完成属性值的注入
容器:存储对象,使用map结构来存储,在spring中一般存在三级缓存,singletonObjects存放完整的bean对象。bean的整个生命周期从创建到使用到销毁的过程,全部都是由容器来管理。
分:
1、容器创建(beanFactory, DefaultListableBeanFactory),向bean工厂中设置一些参数(BeanPostProcessor, Aware接口的子类)等属性。
2、加载解析bean对象,准备要创建的bean对象的定义对象beanDefinition(xml或者注解的解析过程)
3、beanFactoryPostProcessor的处理,此处是扩展点:PlaceHolderConfigurSupport, ConfigurationClassPostProcessor
4、BeanPostProcessor的注册功能,方便后续对bean对象完成具体的扩展功能
5、通过反射的方式讲BeanDefinition对象实例化成具体的bean对象
6、bean对象的初始化过程(自定义对象属性赋值,容器对象属性赋值Aware接口,调用beanPostProcessorBeforeInitialization, 调用init-method方法,调用beanPostProcessorAfterInitialization)
7、生成完整的bean对象,通过getBean方法可以直接获取
8、销毁过程