Spring 初级面试题


一. 什么是 IOC

什么是 IOC: IOC 是一种设计思想, 对象的管理方式由程序员控制变成了由框架控制, 从创建到销毁都是框架管理

spring 是通过什么方式来实现 IOC 的: 通过 DI(依赖注入实现)

什么是 DI: DI, 依赖注入, 就是把对应的属性注入到具体的对象中

二. 什么是 AOP

AOP 是一种编程思想, 是对 OOP 面向对象编程的补充, 目前比较常见的 AOP 方式有 2 种, JDK 自带的动态代理和 CGlib, 我们需要知道一些 AOP 的术语

  • 通知(Advice): 就是我们写的增强对象的代码
  • 连接点(JoinPoint): 可以被切入的点, 如方法调用前, 方法调用后, 方法返回, 方法抛出异常等
  • 切点(PointCut): 真正被你选中的连接点, 那么多连接点, 你并不是所有的地方需要增强
  • 切面(Aspect): 切面是通知和切点的结合, 把通知应用到切点的过程叫切面

三. 什么是 BeanDefinition

我们需要 spring 帮我们管理对象, 起码让 spring 知道我们哪些对象需要被管理, 是否需要单例, 用哪个构造方法创建, 初始化方法是什么 有很多很多东西需要让 spring 知道, 这些东西就封装成 1 个对象, BeanDefinition 就是这种对象实现的接口, 定义了很多获取 Bean 信息的方法

四. BeanFactory 和 FactoryBean

  1. BeanFactory

BeanFactory 是一个接口, 定义了一些基本的方法, springIOC 容器实现了 BeanFactory 接口, 所以可以理解为他就是 spring 容器, 常用的实现类有: ApplicationContext, DefaultListableBeanFactory, ClassPathXmlApplicationContext, AnnotationConfigApplicationContext

  1. FactoryBean

FactoryBean 也是一个接口, 他定义了 1 个 getObject 的方法, 如果需要容器创建的类实现了这个接口, 那么容器会把调用 getObject 方法返回的对象和自己都加入容器, FactoryBean 的名称是在 getObject 名称前面加上 $, 创建比较复杂的对象时, 适合用 FactoryBean

五. 后置处理器(PostProcessor)

  1. BeanFactoryPostProcessor

BeanFactoryPostProcessor 是用来增强容器的, 里面定义了方法 postProcessBeanFactory 方法, 参数是 ConfigurableListableBeanFactory, 这个类实现了 BeanFactory, 传进来的就是 spring 容器本身, 你可以修改里面的 BeanDefinition, 或者手动创建 1 个 BeanDefinition 塞进容器

postProcessBeanFactory 在所有的 BeanDefinition 加载完成后调用

  1. BeanPostProcessor

BeanPostProcessor 是用来增强或处理 Bean 的, 在初始化方法前调用 postProcessBeforeInitialization 方法, 在初始化方法后面调用 postProcessAfterInitialization

六. spring 的创建流程

从 new AnnotationConfigApplicationContext()开始

  1. 父类无参构造方法创建 DefaultListableBeanFactory
  2. 加载配置类, 创建 spring 自身启动需要的对象的 BeanDefinition, 如: 一些后置处理器, 创建需要被 spring 管理的 Bean 的 BeanDefinition
  3. refresh 方法被调用
    1. BeanFactory 的预准备工作, 如:设置类的加载器, 表达式解析器, 加载系统的环境变量等
    2. 先执行 BeanDefinitionRegistryPostProcessor, 再执行 BeanFactoryPostProcessor(根据优先级接口, 或排序接口, 顺序执行)
    3. 创建 BeanPostPreocessor
    4. 执行 BeanPostProcessor(根据优先级接口, 或排序接口, 顺序执行)
    5. 创建事件派发器, 并且注入到容器
    6. 创建所有的监听器, 并绑定到事件派发器中, 然后派发之前步骤产生的事件
    7. finishBeanFactoryInitialization 方法被调用, 初始化剩余的 Bean
      1. 获取剩下的所有的 BeanDefinition
      2. 如果不是抽象的, 并且是单例的, 并且不是懒加载的, 就创建
        1. 如果是 BeanFactory, 调用 getObject 方法
        2. 否则就调用 getBean 方法, getBean 方法会调用 doGetBean 方法 标记点: getBean
          1. 先从缓存中获取 Bean, 判断是否有
          2. 如果没有, 创建 Bean
            1. 获取当前 Bean 依赖的其他 Bean
            2. 如果有依赖的 Bean, 调用 getBean 方法先创建依赖的 Bean, 走递归, 递归点: getBean
            3. 没有依赖, 就调用 createBean
            4. 判断是否需要自定义创建
              1. 调用 resolveBeforeInstantiation 方法, 执行 InstantiationAwareBeanPostProcessor 类型的后置处理器, 返回自定义对象
            5. 不需要自定义就调用, doCreateBean
              1. 调用 createBeanInstance, 创建 Bean 实例
              2. 调用 populateBean, 给对象属性赋值**(使用三级缓存解决循环依赖)**
              3. 调用 Aware 接口的方法
              4. 调用后置处理器的 postProcessBeforeInitialization 方法
              5. 执行初始化方法
              6. 调用后置处理器的 postProcessAfterInitialization 方法**(AOP 在此处完成)**
              7. 注册 Bean 的销毁方法
            6. 把创建的对象塞进容器

七. Bean 的生命周期

  1. 实例化 Bean
  2. 设置对象属性
  3. 调用 Aware 接口方法
  4. BeanPostProcessor 前置处理方法
  5. Bean 的初始化方法
  6. BeanPostProcessor 后置处理方法
  7. 使用中…
  8. 销毁

八. 循环依赖

spring 使用三级缓存解决循环依赖

// 一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 三级缓存 三级缓存value spring扔进去的是一个lambda表达式 
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
// 二级缓存
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
// 扔进三级缓存的lambda表达式
if (earlySingletonExposure) {
   if (logger.isTraceEnabled()) {
       logger.trace("Eagerly caching bean '" + beanName +
                    "' to allow for resolving potential circular references");
   }
   // 这里就是扔进去的lambda表达式
   addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

使用三级缓存是为了解决 AOP 的循环依赖

如果没有 AOP, 二级缓存就可以解决

下图是大概的过程: 并不完整, 为了方便理解, 少了正常 AOP 的过程

在这里插入图片描述

九. spring 事务原理

spring 通过 AOP 实现动态代理, 通过 ThreadLocal 存取数据库连接, 实现事务

十. 事务传播

常量名称常量解释
PROPAGATION_REQUIRED(默认)如果没有, 就新建事务, 如果有就加入
PROPAGATION_REQUIRES_NEW不管外面有没有, 都创建新的事务 (多数据源的时候使用, 下面其他的我都没用过)
PROPAGATION_SUPPORTS如果有事务, 就加入, 如果没有, 不创建
PROPAGATION_MANDATORY必须运行在事务中, 如果没有事务, 就报错
PROPAGATION_NOT_SUPPORTED表示该方法不应该运行在事务中, 如果外面有事务, 挂起该事务
PROPAGATION_NEVER表示该方法不应该运行在事务中, 如果外面有事务, 直接报错
PROPAGATION_NESTED如果没有事务, 开启新事物, 如果有事务, 开启子事务, 事务嵌套, 必须等外面的事务完成才能提交 (具体用途我不清楚)

十一. 事务失效

  1. 方法不是 public

  2. 抛出异常类型错误, 或者被吃掉了

  3. 没有开启事务的 A 方法调用了开启事务的 B 方法, 事务会失效

代理对象内部有 1 个属性是原始对象, 代理对象的 A 方法没有事务,B 方法有事务, 调用过程如下

调用代理对象的 A 方法(没有事务), 代理对象的 A 方法调用原始对象的 A 方法, 原始方法的 A 方法内部调用了 B 方法(此时的 B 方法是原始对象的), 所有事务失效

十二. 哪些设计模式

  • 工厂

spring 自己就可以算是 1 个大工厂, FactoryBean 也算是生产对象的工厂

  • 适配器

AOP 中的 Advice 通知使用了适配器模式

springMVC 的 handler 也使用了适配器模式

  • 装饰器

DataSource 使用了装饰器模式

  • 代理

AOP 就是动态代理

  • 观察者

spring 的事件通知

  • 策略

创建对象的时候使用了策略模式

  • 模板方法

spring 中的 xxxTemplate 都使用了模板方法

十三. spring 整合 mybatis 原理

  1. 扫描包, 获取全部的接口
  2. 注入 1 个 ImportBeanDefinitionRegistrar, 通过 registerBeanDefinitions 方法, 注册 BeanFactory 类型的 BeanDefinition
  3. 通过 BeanFactory, 然后在 getObject 调用 sqlSession.getMapper(Class clazz)生成代理对象
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值