【Java八股-第十五期】Bean - Spring

提纲:

🔥Bean

  • 创建过程

  • 循环依赖

  • 配置方法

  • 作用域

  • 线程安全

🎈面试八股真题

  • 1、Autowired和Resource关键字的区别?

  • 2、依赖注入的方式有几种,各是什么?

  • 3、解释一下spring bean的生命周期

  • 4、解释Spring支持的几种bean的作用域?

  • 5、Spring基于xml注入bean的几种方式?

  • 6、Spring框架中都用到了哪些设计模式?

  • 7、说说Spring 中 ApplicationContext 和 BeanFactory 的区别

  • 8、Spring 框架中的单例 Bean 是线程安全的么?

  • 9、Spring 是怎么解决循环依赖的?

  • 10、说说事务的隔离级别

  • 11、说说事务的传播级别

  • 12、Spring 事务实现方式

  • 13、Spring框架的事务管理有哪些优点

  • 14、事务三要素是什么?

  • 15、事务注解的本质是什么?

一、Bean

1. 创建过程

  • getBean() 查看缓存

    • 1、确认 BeanName,查看缓存中是否存在 Bean 对象,若存在直接返回

    • 2、查看父工厂是否存在

  • createBean() 实例化

    • 1、加载 BeanDefinition,将其转化为 RootBeanDefinition

    • 2、实例化 Bean,调用 Bean 的构造方法进行实例化,若 Bean 是单例,支持循环依赖且正在创建,将一个 SingletonFactory 回调接口放入三级缓存,方法参数为 Bean,BeanName 以及 BeanDefinition,用于暴***ean 的引用和 Bean 的提前 AOP,解决循环依赖问题

  • populateBean() 依赖注入

    • 1、通过 AutowireAnnotation 注解扫描 @Autowired/@Value/@Lazy/@Optional 等注解,CommonAnnotation扫描 @Resource 注解进行后置处理器装配

    • 2、通过 xml 文件配置的 setter/构造 方法进行注入

  • initializeBean() 初始化 Bean

    • 1、若 Bean 实现了 Aware 接口,如 BeanNameAware、BeanClassLoaderAware 等,通过 ApplicationAware后置处理器进行调用

    • 2、若 Bean 有 @PostConstruct 注解标注的方法,使用 CommonAnnotation 后置处理器进行调用

    • 3、调用 Bean 实现的 InitializingBean 接口的 affterPropertiesSet 方法

    • 4、调用 xml 文件中配置的 init-method 方法

    • 5、通过 AspectJ***Creator 后置处理器,进行 Bean 的 AOP 增强,生成代理对象并放入单例池

2.循环依赖

  • Spring 无法自行解决的循环依赖

    • 1、Prototype 作用域的 Bean 的循环依赖:每一次获取 Bean 都会创建新的 Bean 对象,不会检查任何缓存

    • 2、通过构造方法注入的 Bean 的循环依赖:循环依赖发生在实例化阶段,无法提前暴露对象的引用来解决

  • Spring 只可以解决单例 Bean 在依赖注入阶段发生的循环依赖

    • 三级缓存

      • 1、SingletonObject:一级缓存,存放已经创建好的 Bean,ConcurrentHashMap

      • 2、EarlySingletonObject:二级缓存,存放正在创建的已经实现 AOP 的 Bean 对象,HashMap

      • 3、SingletonFactory:三级缓存,存放 SingletonFactory,本质上是存放一个回调接口,用于提前暴***ean 的引用和实现 Bean 的提前 AOP

  • 原理:假设 A—B 循环依赖

    • 1、实例化 A 对象,将 A 对象的引用、A 的 BeanName,A 的 BeanDefinition 作为参数传给回调接口,即 SingletonFactory 接口的getEarlyBeanReference() 方法,并将其作为 Value 存入三级缓存

    • 2、依赖注入 B 对象,递归创建 B 对象

    • 3、B 对象的依赖注入阶段,依赖注入了 A,此时先去二级缓存中查看是否存在 A 的提前引用,若存在直接取出使用,若不存在,从三级缓存中取出 A 的 SingletonFactory,调用 SingletonFactory 的 getObject 方法,对 A 进行提前 AOP,获取 A 的早期代理对象,并放入二级缓存

  • 问题

    • 1、第三级缓存:第三级缓存是解决循环依赖的核心,它通过提前暴露 A 在创建时的引用,来解决循环依赖,但不能简单的存放实例化得到的 A 的普通对象引用,假设存放的是 A 的普通对象,那 B 在依赖注入时获得的就是没有经过 AOP 增强的 A 对象,因此需要存放一个 SingletonFacotry 回调接口,并传入创建 A 的 BeanName、Bean、BeanDefinition 信息,在 B 依赖注入 A 时,就可以调用回调接口的 getObject 方法,对 A 进行提前 AOP,获取 A 的早期代理对象

    • 2、第二级缓存:第二级缓存用于存放 A 的创建中对象的引用,假设 A-B循环依赖,A-C 也循环依赖,若没有第二级缓存,C 在注入 A 时,也会从三级缓存中取出 SingletonFactory 进行 AOP,生成代理对象,这样就破坏了 A 的单例性,因此在实际源码中,会采用 Double check 的方式,对二级缓存中是否存在 A 对象进行判断,并在 Synchronize 同步代码块中,调用 SingletonFactory 的 getObject 方法,调用完后放入二级缓存,并删除三级缓存中的 SingletonFactory,因此,二级缓存的 put 方法和三级缓存的 remove 方法都是绑定出现的,使用 ConcurrentHashMap 无法保证多个操作组合的原子性,只能加锁,所以二级缓存与三级缓存使用的是 HashMap 而不是 ConcurrentHashMap

3.配置方法

  • xml 文件配置

    • 1、set 方法,在 xml 文件中配置 setter 方法的 ref 参数为一个 BeanName 来注入

    • 2、构造方法,和 set 方法类似

    • 3、接口,代码侵入大,不利于理解,麻烦,不用

  • @Autowired 注解与 @Resource 注解

    • 1、前者是 Spring 的注解,由 AutowireAnnotation 后置处理器扫描,后者是 Java 本身的注解,由 CommonAnnotation 后置处理器扫描

    • 2、前者默认按类型(ByType)进行装配,并默认 Bean 必须存在,后者默认按 BeanName (ByName)进行装配

  • @Component 及衍生的语义注解

4.作用域

  • singleton:单例,Spring 的单例指的是 BeanName 的单例,而不是 Bean 的类型的单例

  • prototype:多例,每一次获取创建一个 Bean

  • request:在 request 域内单例,即一个 request 使用一个实例,生命周期随 request

  • session:类似 request,按 session 会话域算

  • golobal-session:所有会话共享一个实例

5.线程安全

  • prototype:线程安全的,每一个线程都有自己的 Bean

  • 无状态 singleton:线程安全,不存储状态,没有可以改变的共享变量

  • 有状态 singleton:最好不要定义有状态 Bean 的 singleton,实在要用,可以用分布式锁的同步解决方式,也可以用ThreadLocal 的异步方式

二、面试八股真题🎈🎈🎈

1、Autowired和Resource关键字的区别?

  • @Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。

  • 1、共同点

    • 两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法。

  • 2、不同点

    • (1)@Autowired

      • @Autowired为Spring提供的注解,需要导入包org.springframework.beans.factory.annotation.Autowired;只按照byType注入。

      • @Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。如下:

    • (2)@Resource

      • @Resource默认按照ByName自动注入,由J2EE提供,需要导入包javax.annotation.Resource。

      • @Resource有两个重要的属性:name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性,这时将通过反射机制使用byName自动注入策略。

      • 注:最好是将@Resource放在setter方法上,因为这样更符合面向对象的思想,通过set、get去操作属性,而不是直接去操作属性。

      • @Resource装配顺序:

        • ①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。

        • ②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。

        • ③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。

        • ④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。

      • @Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入。

2、依赖注入的方式有几种,各是什么?

  • 一、构造器注入

    • 将被依赖对象通过构造函数的参数注入给依赖对象,并且在初始化对象的时候注入。

    • 优点:

      • 对象初始化完成后便可获得可使用的对象。

    • 缺点:

      • 当需要注入的对象很多时,构造器参数列表将会很长; 不够灵活。若有多种注入方式,每种方式只需注入指定几个依赖,那么就需要提供多个重载的构造函数,麻烦。

  • 二、setter方法注入

    • IoC Service Provider通过调用成员变量提供的setter函数将被依赖对象注入给依赖类。

    • 优点:

      • 灵活。可以选择性地注入需要的对象。

    • 缺点:

      • 依赖对象初始化完成后由于尚未注入被依赖对象,因此还不能使用。

  • 三、接口注入

    • 依赖类必须要实现指定的接口,然后实现该接口中的一个函数,该函数就是用于依赖注入。该函数的参数就是要注入的对象。

    • 优点 :

      • 接口注入中,接口的名字、函数的名字都不重要,只要保证函数的参数是要注入的对象类型即可。

    • 缺点:

      • 侵入性太强,不建议使用。

    • PS:什么是侵入性? 如果类A要使用别人提供的一个功能,若为了使用这功能,需要在自己的类中增加额外的代码,这就是侵入性。

3、解释一下spring bean的生命周期

  • 首先说一下Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;

  • Spring上下文中的Bean生命周期也类似,如下:

    • (1)实例化Bean:

      • 对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。

    • (2)设置对象属性(依赖注入):

      • 实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。

    • (3)处理Aware接口:

      • 接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的x

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

代码鹿のJAVA八股面试题总结 文章被收录于专栏

【📫专栏目录在最底部📫】 - 本专栏适合于JAVA已经入门的学生或人士,有一定的编程基础。 - 本专栏特点: 本专刊囊括了JAVA、Spring、计算机网路、操作系统、计算机网络、MySQL、算法与数据结构、中间件等一系列知识点,总结出了高频面试考点(附有答案),事半功倍,为大家春秋招助力。 - 本专栏内容分为五章

全部评论

相关推荐

做牛做马大喷菇:很难不怀疑是包装的,你简历上的内容,三年经验都挺难做出来
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务