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种事务传播机制:

  1. REQUIRED:默认的传播特性,如果当前没有事务,则新建一个事务;如果当前存在事务,则加入这个事务
  2. SUPPORTS:当前存在事务,则加入当前事务;如果当前没有事务,则以非事务的方式执行
  3. MANDATORY:当前存在事务,则加入当前事务;如果当前事务不存在,则抛出异常
  4. REQUIRED_NEW:创建一个新事务,如果存在当前事务,则挂起该事务
  5. NOT_SUPPORTED:以非事务方式执行,如果存在当前事务,则挂起当前事务
  6. NEVER:不使用事务,如果当前事务存在,则抛出异常
  7. 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事务什么时候会失效?

  1. 未被spring管理:使用Spring事务的前提是,对象要被Spring管理,事务方法所在的类要被加载为bean对象
  2. 数据库不支持事务:以MySQL为例,InnoDB引擎是支持事务的,而像MyISAM、MEMORY等是不支持事务的
  3. 事务方法没有被public修饰:java的访问权限修饰符有4种,private、default、protected、public四种,但是@Transactional注解只能作用于public修饰的方法上
  4. 使用final修饰了方法:如果事务方法使用final修饰,那么aop就无法在代理类中重写该方法,事务就不会生效。同样的,static修饰的方法也无法通过代理变成事务方法。
  5. 同一个类中方法调用:同一个类中的方法没有事务,在该方法中调用一个有事务的方法,那么该事务也无效。因为调用的是类本身的方法,而不是代理对象的方法。
  6. 多线程调用:因为两个操作不在一个线程中,获取到的数据库连接不一样,从而是两个不同的事务,所以也不会回滚。
  7. 错误的传播行为:Spring定义了7种传播行为,我们可以通propagation属性来指定传播行为参数,目前只有REQUIRED、REQUIRES_NEW、NESTED会创建新的事务,其他的则会以非事务的方式运行或者抛出异常
  8. 自己try...catch...掉了异常:如果没有异常抛出,则Spring认为程序是正常的,就不会回滚
  9. 手动抛出了错误的异常:Spring默认只会回滚RuntimeException和Error对于普通的Exception,不会回滚。如果你想触发其他异常的回滚,需要在注解上配置一下,如:@Transactional(rollbackFor = Exception.class)
    10.嵌套事务回滚多了:即内层事务出现异常,因为没有try,catch住,导致外层事务页进行了回滚。

5、spring支持的bean的作用域有哪些?

  1. singleton:默认的作用域,单例Bean,每个Spring IOC容器中只有一个bean的实例
  2. prototype:原型模式,每次用getBean方法获取prototype定义的bean的时候,都会产生一个新的Bean的实例;
  3. request:为每一个request请求创建一个bean的实例,在这个请求完成之后,这个bean就会失效,然后被Spring的垃圾回收站回收;
  4. session:与request的范围基本相似,同一个session会话共享一个bean的实例,不同session会话之间使用的是不同的bean的实例,只有在Web应用中使用Spring的时候,该作用域才会有效;
  5. 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、销毁过程

猜你喜欢

转载自blog.csdn.net/xueping_wu/article/details/126441375