文章目录

  • Spring Beans
  • 什么是Spring beans
  • 配置Bean的几种方式
  • Spring实例化bean方式的几种方式
  • Spring框架中的单例bean是线程安全的吗
  • 释Spring框架中bean的生命周期
  • Spring是如何解决Bean的循环依赖
  • 二级缓存能不能解决循环依赖?
  • Spring有没有解决多例Bean的循环依赖?
  • Spring有没有解决构造函数参数Bean的循环依赖?
  • BeanFactory的作用
  • Bean的创建顺序
  • Spring其他
  • Spring事件监听的核心机制
  • Spring是如何整合MyBatis将Mapper接口注册为Bean的原理

Spring Beans

什么是Spring beans

在 Spring 中,构成应用程序主干并由 Spring IOC 容器管理的对象称为bean。bean 是一个由 Spring IOC 容器实例化、组装和管理的对象。

配置Bean的几种方式

  1. xml: <bean class="com.tuling.UserService" id="">
  2. 注解:@Component(@Controller 、@Service、@Repostory) 前提:需要配置扫描包<component-scan> 反射调用构造方法
  3. javaConfig: @Bean 可以自己控制实例化过程
  4. @Import 3种方式

Spring实例化bean方式的几种方式

  1. 构造器方式(反射)
  2. 静态工厂方式;factory-method
  3. 实例工厂方式(@Bean);factory-bean+factory-method
  4. FactoryBean方式

Spring框架中的单例bean是线程安全的吗

不是,Spring框架中的单例bean不是线程安全的。
spring 中的 bean 默认是单例模式,spring 框架并没有对单例 bean 进行多线程的封装处理。
实际上大部分时候 spring bean 无状态的(比如 dao 类),所以某种程度上来说 bean 也是安全的,但如果 bean 有状态的话(比如 view model 对象),那就要开发者自己去保证线程安全了,最简单的就是改变 bean 的作用域,把“singleton”变更为“prototype”,这样请求 bean 相当于 new Bean()了,所以就可以保证线程安全了。

释Spring框架中bean的生命周期

Bean生命周期:指定的就是Bean从创建到销毁的整个过程: 分4大步:

  1. 实例化
    a. 通过反射去推断构造函数进行实例化
    b. 实例工厂、 静态工厂
  2. 属性赋值
    a. 解析自动装配(byname bytype constractor none @Autowired) DI的体现
    b. 循环依赖
  3. 初始化
    a. 调用XXXAware回调方法
    b. 调用初始化生命周期回调(三种)
    c. 如果bean实现aop 创建动态代理
  4. 销毁
    a. 在spring容器关闭的时候进行调用
    b. 调用销毁生命周期回调

Spring是如何解决Bean的循环依赖

采用三级缓存解决的就是三个Map,关键: 一定要有一个缓存保存它的早期对象作为死循环的出口

  1. 一级缓存:存储完整的Bean
  2. 二级缓存: 避免多重循环依赖的情况 重复创建动态代理。
  3. 三级缓存:
    a. 缓存是函数接口:通过lambda 把方法传进去( 把Bean的实例和Bean名字传进去(aop创建) )
    b. 不会立即调:(如果在实例化后立即调用的话:所有的aop 不管bean是否循环依赖都会在 实例化后创建
    proxy, 正常Bean 其实spring还是希望遵循生命周期在初始化创建动态代理, 只能循环依赖才创建)
    c. 会在 ABA (第二次getBean(A) 才会去调用三级缓存(如果实现了aop才会创建动态代理,如果没有实现
    依然返回的Bean的实例))
    d. 放入二级缓存(避免重复创建)
二级缓存能不能解决循环依赖?

a. 如果只是死循环的问题: 一级缓存就可以解决 :无法避免在并发下获取不完整的Bean
b. 二级缓存也可以解决循环依赖: 只不过如果出现重复循环依赖 会多次创建aop的动态代理

Spring有没有解决多例Bean的循环依赖?

a. 多例不会使用缓存进行存储(多例Bean每次使用都需要重新创建)
b. 不缓存早期对象就无法解决循环

Spring有没有解决构造函数参数Bean的循环依赖?

a. 构造函数的循环依赖也是会报错
b. 可以通过人工进行解决:@Lazy
i. 就不会立即创建依赖的bean了
ii. 而是等到用到才通过动态代理进行创建

BeanFactory的作用

  1. BeanFactory是Spring中非常核心的一个顶层接口;
  2. 它是Bean的“工厂”、它的主要职责就是生产Bean;
  3. 它实现了简单工厂的设计模式,通过调用getBean传入标识生产一个Bean;
  4. 它有非常多的实现类、每个工厂都有不同的职责(单一职责)功能,最强大的工厂是:DefaultListableBeanFactory
    Spring底层就是使用的该实现工厂进行生产Bean的
  5. BeanFactory也是容器,Spring容器(管理着Bean的生命周期)

Spring 提供的策略类 spring相关问题_Spring 提供的策略类

Bean的创建顺序

Bean的创建顺序是由BeanDefinition的注册顺序来决定的,当然依赖关系也会影响Bean创建顺序
BeanDefinition的注册顺序主要是由注解(配置)的解析顺序来决定:

  1. @Configuration
  2. @Component
  3. @Import—类
  4. @Bean
  5. @Import—ImportBeanDefinitionRegistrar

Spring其他

Spring事件监听的核心机制

原理:观察者模式
支持异步:
异步发布事件的核心机制:多线程

spring的事件监听有三个部分组成:
事件 (ApplicationEvent) 负责对应相应监听器 事件源发生某事件是特定事件监听器被触发的原因。
监听器 (ApplicationListener) 对应于观察者模式中的观察者。监听器监听特定事件,并在内部定义了事件发生后的响应逻辑。
事件发布器 (ApplicationEventMulticaster )对应于观察者模式中的被观察者/主题, 负责通知观察者 对外提供发布事件和增删事件监听器的接口,维护事件和事件监听器之间的映射关系,并在事件发生时负责通知相关监听器。

Spring是如何整合MyBatis将Mapper接口注册为Bean的原理

  1. 首先MyBatis的Mapper接口核心是JDK动态代理
  2. Spring会排除接口,无法注册到IOC容器中
  3. MyBatis 实现了BeanDefinitionRegistryPostProcessor 可以动态注册BeanDefinition
  4. 需要自定义扫描器(继承Spring内部扫描器ClassPathBeanDefinitionScanner ) 重写排除接口的方法(isCandidateComponent)
  5. 但是接口虽然注册成了BeanDefinition但是无法实例化Bean 因为接口无法实例化
  6. 需要将BeanDefinition的BeanClass 替换成JDK动态代理的实例(偷天换日)
  7. Mybatis 通过FactoryBean的工厂方法设计模式可以自由控制Bean的实例化过程,可以在getObject方法中创建JDK动态代理