Spring 面试突击

一、bean

  1. 概念: Spring管理的对象实例

  2. 作用域:

    • singleton:单例模式下,一个类只会存在一个实例对象,是线程不安全的,但是只要不在类中声明一些类的成员变量,仅仅是方法调用方法的话,虽然是线程不安全,但是不会发生线程同步问题
    • prototype:多例,每次容器获取bean的时候都会创建一个新的实例
    • request:在一次http请求中,只会创建一个bean的实例,只在该请求内有效,而且会随请求的结束而销毁
    • session:在一次session请求中,只会创建一个实例
    • global session:在一个全局session请求中,只会创建一个实例
  3. bean的生命周期:
    ① 实例化:
    spring容器根据xml配置,或者注解扫描到要由它管理的bean,获取bean的元数据,通过工厂模式,以反射的方式,实例化bean
    ② 依赖注入:
    根据配置文件或注解中定义的bean的依赖关系,通过依赖注入(DI),注入bean的依赖对象
    ③ 功能增强:
    这里包括:检查是否实现了aware系列接口、是否实现了beanPostProcess系列接口(beanPostProcess包括了前置与后置方法,后置方法在初始化后进行,aop就在这一个环节实现)

    • 实现aware接口,可以让bean感知并获取到自己在容器中的一些信息,比如所在的容器名等等
    • 实现beanPostProcess接口,可以在bean初始化前后执行一些其他的方法,定制化bean

    ④ 初始化bean
    ⑤ 使用bean
    ⑥ 销毁bean

二、IOC

  1. 概念:
    控制反转,原本一个类的对象实例的创建是在程序员在用到的时候手动创建,耦合度较高,在spring中,spring容器根据.xml配置或者注解去实例化所有的bean,管理bean与bean之间的依赖注入,一方面让系统耦合度降低,另一方面,也提高了系统的资源管理效率(默认情况下,bean是单例的)
  2. 实现原理:
    ①:Spring初始化时,会根据配置文件或者注解扫描所有需要容器管理的bean,获取它们的元数据(BeanDifination)
    ②:Spring容器(BeanFactory、ApplicationContext)会根据BeanDifinition通过反射的方式,实例化Bean实例
    ③:根据配置文件或者注解中定义的依赖关系,完成依赖注入
    ④:依赖注入后,进行初始化工作(在这前后还可以根据aware、beanPostprocess接口的前置后置方法进行bean功能的增加环节)
    ④:将配置完成的bean放入单例池(默认情况下),在需要时取出

三、DI

  1. 概念: 依赖注入,为bean实例中的引用对象,注入具体的实例

  2. 依赖注入的两种主要方式:

    • 构造方法注入:通过构造方法入参的方式注入,优点是能保证在bean实例化的时候,依赖都能被注入,如果注入失败会报错,缺点是当依赖项过多时,代码冗余,且不能可选注入部分依赖,总得来说,安全但不足够灵活

      public class A {
          private B b; //  A中注入实例 b
      
          public A(B b) {
              this.b = b;
          }
      }
      
    • set方法注入:通过set方法的方式注入,优点是足够灵活,可选部分注入,但是不能保证实例化时,一定注入了依赖,注入失败在编译时也不会报错,只有使用到了才会报错,总的来说,灵活但不足够安全

      public class A {
          private B b;
      
          public void setB(B b) {
              this.b = b;
          }
      }
      
  3. 循环依赖:

    • 问题描述:以上面的代码为例,A中依赖了B,因此,在A实例化以后,需要注入B的实例,但是,如果此时B也依赖了A,要注入B的实例就必须在B中也注入A的实例,这样就形成了一个循环,两个bean都无法完成属性注入

    • 解决方案:通过三级缓存的方式解决

      三级缓存:

      • 一级缓存:存放了创建中的bean实例,对应bean的实例化阶段
      • 二级缓存:存放了没有完成属性填充的bean对象,但是已经实例化了
      • 三级缓存:存放了已经完成属性填充的完整bean实例
      • 具体过程:
        1. 创建A的实例,放入一级缓存,此时A是创建中的状态
        2. 创建B的实例,放入一级缓存
        3. 对A进行属性填充,此时需要拿到B对象实例,因为B没有完成依赖注入,所以去一级缓存中寻找,如果找到就注入,如果没有找到,就从二级缓存中找到B实例,这里相当于将未完成属性填充的B提前暴露出来,用于完成A的属性填充,从而打破循环,反过来将A提前暴露给B也是一样的
        4. 将依赖注入完成的AB放入三级缓存,用于接下来的bean初始化

四、AOP

  1. 概念: 面向切面编程

  2. 原理:
    ①. 在对象初始化完成后,Spring会检查bean是否需要进行AOP,这个环节是在bean后置处理器的后置处理环节进行的
    ②. 如果需要进行AOP,那么就会为该bean创建一个动态代理对象
    ③. 动态代理对象中,注入被代理对象作为依赖,用被代理对象执行原方法,而在原方法外面,实现增强方法,从而完成AOP的过程
    ④. 在需要用到这个类实例的地方,注入动态代理类的实例,而不是被代理类的实例,这样就可以横向地在原本的代码上添加新的逻辑功能

  3. 动态代理的方式:

    • JDK动态代理:默认使用的代理方式,需要被代理类实现接口,因为它需要根据接口,反射创建出代理对象
    • CGLIB动态代理:不需要被代理类实现接口,通过修改字节码文件的方式,为被代理类创建一个子类的代理对象

五、事务

  1. 概念: Spring保证一组操作要么全部成功要么全部失败的机制。通过让着组操作达到原子性、持久性、具有隔离性、从而实现数据的一致性

  2. 实现原理:
    spring会通过AOP的方式,在方法执行前开启事务,在方法执行结束后,根据是否报错,决定是回滚还是提交事务

  3. 传播机制:
    通过@Transaction(propagation=propagation.xxx)
    ① required:如果已经存在一个事务则加入这个事务,如果不存在事务就创建一个事务
    ② supports:支持当前事务,如果没有事务就以非事务执行
    ③ mandatory:支持当前事务,如果没有事务就报错
    ④ requiem_new:新建事务,如果已经存在事务,就将它挂起
    ⑤ not_supported:以非事务执行,如果已经存在事务,就将它挂起
    ⑥ never:以非事务执行,如果已经存在事务,就报错
    ⑦ nested:如果已经存在事务,则在事务内嵌套执行(外层回滚内层也会回滚,内层回滚外层不受影响),如果没有事务,则创建一个事务

  4. 事务失效的场景:
    ① 没有正确声明事务:事务可以通过编程式(使用TransactionTemplate或TransactionTemplate在代码中进行事务管理)和声明式(使用注解)的方式声明
    ② 没有正确处理异常:通过声明式的方式开启事务时,只能捕获运行时异常,其他异常无法捕获,也就不能完成事务回滚
    ③ 没有使用代理对象:在进行事务时,没有使用Spring管理的代理对象,而是直接new一个对象去执行事务方法,导致AOP不能进行,事务失败
    ④ 在事务方法内部调用非事务方法,并且没有设置合适的传播机制

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值