spring 手动提交事务_spring疑难面试题汇总

Spring的IOC/AOP的实现

IOC(Inversion of Control)

  • IOC是指容器控制程序对象之间的关系,控制权由应用代码中转到了外部容器,控制权的转移是所谓反转。 对于Spring而言,就是由Spring来控制对象的生命周期和对象之间的关系。
  • IOC还有另外一个名字依赖注入(Dependency Injection)。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,即由容器动态地将某种依赖关系注入到组件之中。
  • 在Spring的工作方式中,所有的类都会在spring容器中登记,告诉spring这是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。
  • 在系统运行中,动态的向某个对象提供它所需要的其他对象。
  • 依赖注入的思想是通过反射机制实现的,在实例化一个类时,它通过反射调用类中set方法将事先保存在HashMap中的类属性注入到类中。 总而言之,在传统的对象创建方式中,通常由调用者来创建被调用者的实例,而在Spring中创建被调用者的工作由Spring来完成,然后注入调用者,即所谓的依赖注入or控制反转。 注入方式有两种:依赖注入和设置注入; IoC的优点:降低了组件之间的耦合,降低了业务对象之间替换的复杂性,使之能够灵活的管理对象。

AOP(Aspect Oriented Programming)

  • AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块。将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,比如日志记录,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
  • 实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。
  • Spring实现AOP:JDK动态代理和CGLIB代理
  • JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理;其核心的两个类是InvocationHandler和Proxy。
  • CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强;需要引入包asm.jar和cglib.jar。 使用AspectJ注入式切面和@AspectJ注解驱动的切面实际上底层也是通过动态代理实现的。

Spring如何解决循环依赖

什么是循环依赖?

2个或以上bean 互相持有对方,最终形成闭环。

循环依赖可能出现的三种方式

  1. 构造器参数循环依赖
  2. setter方式单例,默认方式
  3. setter方式原型,prototype

三级缓存解决循环依赖

  • 第一级缓存:单例缓存池 singletonObjects。用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用
  • 第二级缓存:早期提前暴露的对象缓存 earlySingletonObjects,存放原始的 bean 对象(尚未填充属性),用于解决循环依赖
  • 第三级缓存:singletonFactories 单例对象工厂缓存

Spring的后置处理器

BeanPostProcessor

如果我们想在Spring容器中完成bean实例化、配置以及其他初始化方法前后要添加一些自己逻辑处理。我们需要定义一个或多个BeanPostProcessor接口实现类,然后注册到Spring IoC容器中。

BeanPostProcessor后置处理器在bean初始化前后进行一些处理工作。

提供两个方法

bean初始化之前做一些处理

postProcessBeforeInitialization

bean初始化之后做一些处理

postProcessAfterInitialization

InstantiationAwareBeanPostProcessor

主要在实例化bean前后工作; AOP创建代理对象就是通过该接口实现。

BeanFactoryPostProcessor

bean工厂的后置处理器,在bean定义(bean definitions)加载完成后,bean尚未初始化前执行。

BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor继承于BeanFactoryPostProcessor。其自定义的方法postProcessBeanDefinitionRegistry会在bean定义(bean definitions)将要加载,bean尚未初始化前真执行,即在BeanFactoryPostProcessor的postProcessBeanFactory方法前被调用。

Spring的@Transactional如何实现的?

@Transactional是spring中声明式事务管理的注解配置方式,相信这个注解的作用大家都很清楚。@Transactional注解可以帮助我们把事务开启、提交或者回滚的操作,通过aop的方式进行管理。通过@Transactional注解就能让spring为我们管理事务,免去了重复的事务管理逻辑,减少对业务代码的侵入,使我们开发人员能够专注于业务层面开发。

默认情况下,数据库处于自动提交模式。每一条语句处于一个单独的事务中,在这条语句执行完毕时,如果执行成功则隐式的提交事务,如果执行失败则隐式的回滚事务。

事务管理,是一组相关的操作处于一个事务之中,因此必须关闭数据库的自动提交模式。这点,Spring会在org/springframework/jdbc/datasource/DataSourceTransactionManager.java中将底层连接的自动提交特性设置为false。

Spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。Spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。

默认配置下,Spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚)。而抛出checked异常则不会导致事务回滚。

Spring也支持明确的配置在抛出哪些异常时回滚事务,包括checked异常。也可以明确定义哪些异常抛出时不回滚事务。还可以编程性的通过setRollbackOnly()方法来指示一个事务必须回滚,在调用完setRollbackOnly()后你所能执行的唯一操作就是回滚。

Spring的事务传播级别

支持当前事务的情况

  • TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  • TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)

不支持当前事务的情况

  • TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。

其他情况

  • TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

BeanFactory和ApplicationContext的联系和区别

实现BeanFactory接口的简单容器,具备最基本功能

实现ApplicationContext接口的复杂容器,具备高级功能

联系

  1. ApplicationContext接口是由BeanFactory接口派生而来,因而提供BeanFactory所有的功能。

区别

  1. BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误。
  2. BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,BeanFactory需要手动注册,而ApplicationContext则是自动注册
  3. ApplicationContext是对BeanFactory的扩展,提供了更多的功能:国际化处理、事件传递、Bean自动装配、各种不同应用层的Context实现

高并发系统的限流如何实现?

  • 缓存:缓存的目的是提升系统访问速度和增大系统处理容量。
  • 降级:降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。
  • 限流:限流的目的是通过对并发请求进行限速,或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率则可以进行拒绝服务、排队或等待、降级等处理。

限流算法主要有4种:

  1. 计数器
  2. 滑动时间窗口算法
  3. 令牌桶算法
  4. 漏桶算法

高并发秒杀系统的设计

难点

  • 短时间内高并发,系统负载压力大
  • 竞争的资源有限,数据库锁冲突严重
  • 避免对其他业务的影响

优化

限流

对于秒杀系统来说,系统的瓶颈一般在数据库层,由于资源是有限的,如库中共1万张票,一瞬间并发进来100万的请求,那么有99万都是无用的请求,所以为了更好的保护底层有限的数据库资源,尽量将请求拦截在上游。

缓存

缓存不但极大的缩短了数据的访问效率,更重要的是承载了底层数据库的访问压力,所以对于读多写少的业务场景充分利用好缓存

热点隔离

业务隔离:如12306的分时段售票,将热点数据分散处理,来降低系统负载压力

系统隔离:实现系统的软硬隔离,不光是实现软件的隔离,还可以实现硬件的隔离,尽最大限度的减少秒杀带来的高并发安全性问题。

数据隔离:启用单独的cache集群或数据库来存放热点数据

队列

将请求放入队列排队处理,以可控的速度来访问底层DB

异步

如将秒杀成功的订单通知信息通过消息队列(RabbitMQ、Kafka)来异步处理

数据库

读写分离、分表分库

负载均衡如何设计?

负载均衡(Load Balancer)是指把用户访问的流量,通过「负载均衡器」,根据某种转发的策略,均匀的分发到后端多台服务器上,后端的服务器可以独立的响应和处理请求,从而实现分散负载的效果。负载均衡技术提高了系统的服务能力,增强了应用的可用性。

负载均衡算法

  1. 随机算法:如果各台服务器权重一样,使用随机算法选择一台服务器;否则,按照权重比率选择服务器。适应于服务器参数一致场景。
  2. 一致性哈希算法:相同参数的请求总是发到同一提供者,当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。缺省用 160 份虚拟节点。适应于服务器参数一致场景。
  3. 加权轮询算法:如果各台服务器权重一致,按照轮询选择服务器,否则,按照权重加权选择。适应于服务器参数不一致场景。
  4. 最小连接数算法:获取各台服务的活跃数(未处理的请求数),如果都不相等,选择最小活跃数对应的服务器,否则,判断各台服务器的权重是否相同,如果不同,按照权重加权随机选择,否则,随机选择。适应于服务器参数一致场景。

自适应负载均衡能力要求

  1. Gateway(Consumer) 端能够自动根据服务处理能力变化动态最优化分配请求保证较低响应时间,较高吞吐量
  2. Provider 端能自动进行服务容量评估,当请求数量超过服务能力时,允许拒绝部分请求,以保证服务不过载
  3. 当请求速率高于所有的 Provider 服务能力之和时,允许 Gateway( Consumer ) 拒绝服务新到请求。

计算权重流程

开始接受请求:服务器都还没接收到请求时,按照轮询算法打流量,目的是为了获取各台服务器的参数,参数包括:平均处理请求时长,每台服务器的活跃数。计算新权重:每台服务器都接收到请求后,根据返回参数计算每台服务器的权重,权重的计算依据每台服务器的平均处理请求时长。weigth = weight + (500 / 平均处理时长)即平均处理时长越短,新权重会越大。按照新权重加权按照概率随机打流量。

f90e5644f9554ec66346153f281d0571.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值