写点什么

Java 岗大厂面试百日冲刺 - 日积月累,每日三题【Day26】—

  • 2021 年 11 月 11 日
  • 本文字数:2135 字

    阅读完需:约 7 分钟

面试题 1:Bean 的加载过程是怎样的?


===================================================================================


我们知道, Spring 的工作流主要包括以下两个环节:


  • 解析,读 xml 配置,扫描类文件,从配置或者注解中获取 Bean 的定义信息,注册一些扩展功能。

  • 加载,通过解析完的定义信息获取 Bean 实例。


下面是跟踪了 getBean的调用链创建的流程图,为了能够很好地理解 Bean 加载流程,省略一些异常、日志和分支处理和一些特殊条件的判断。





从上面的流程图中,可以看到一个 Bean 加载主要会经历这么几个阶段(标绿内容):


  1. 获取 BeanName,对传入的 name 进行解析,转化为可以从 Map 中获取到 BeanDefinition 的 bean name。

  2. 合并 Bean 定义,对父类的定义进行合并和覆盖,如果父类还有父类,会进行递归合并,以获取完整的 Bean 定义信息。

  3. 实例化,使用构造或者工厂方法创建 Bean 实例。

  4. 属性填充,寻找并且注入依赖,依赖的 Bean 还会递归调用 getBean 方法获取。

  5. 初始化,调用自定义的初始化方法。

  6. 获取最终的 Bean,如果是 FactoryBean 需要调用 getObject 方法,如果需要类型转换调用 TypeConverter 进行转化。


以上便是 Spring 对 bean 解析注册的全过程,总结一下大致步骤:


  • 加载 XML 文件,封装成 Resource 对象;

  • 调用 Reader 对象方法读取 XML 文件内容,并将相关属性放到 BeanDefinition 实例;

  • 将 BeanDefinition 对象放到 BeanFactory 对象,用于调用;


追问 1:什么是循环依赖?




举个例子,这里有三个类 A、B、C,然后 A 关联 B,B 关联 C,C 又关联 A,这就形成了一个循环依赖。如果是方法调用是不算循环依赖的,循环依赖必须要持有引用



循环依赖发生的场景:


  • 构造器循环依赖:依赖的对象是通过构造器传入的,发生在实例化 Bean 的时候。

  • 设值循环依赖:依赖的对象是通过 setter 方法传入的,对象已经实例化,发生属性填充和依赖注入的时候。


如果是构造器循环依赖,本质上是无法解决的。比如我们准调用 A 的构造器,发现依赖 B,于是去调用 B 的构造器进行实例化,发现又依赖 C,于是调用 C 的构造器去初始化,结果依赖 A,整个形成一个死结,导致 A 无法创建。


如果是设值循环依赖,Spring 框架只支持单例下的设值循环依赖。Spring 通过对还在创建过程中的单例,缓存并提前暴露该单例,使得其他实例可以引用该依赖。


追问 2:循环依赖得解决思路是什么样的?




Spring 解决循环依赖,主要的思路就是依据三级缓存(解链)。


在实例化 A 时调用 doGetBean,发现 A 依赖的 B 的实例,此时调用 doGetBean 去实例 B,实例化的 B 的时候发现又依赖 A,如果不解决这个循环依赖的话此时的 doGetBean 将会无限循环下去,导致内存溢出,程序奔溃。


如果 Spring 引用一个早期对象,并且把这个"早期引用"并将其注入到容器中,让 B 先完成实例化,此时 A 就获取 B 的引用,完成实例化。


一级缓存:singletonObjects,存放完全实例化属性赋值完成的 Bean,直接可以使用。


二级缓存:earlySingletonObjects,存放早期 Bean 的引用,尚未属性装配的 Bean


三级缓存:singletonFactories,三级缓存,存放实例化完成的 Bean 工厂。





课间休息,来秀一下新加入的一名家庭成员,小哈!来的第二天睡觉就如此妖娆了么~




面试题 2:@Resource 和 @Autowired 有什么区别?


==============================================================================================


  • @Autowired 根据类型注入

  • @Resource 默认根据名字注入,其次按照类型搜索

  • @Autowired @Qualifie("userService") 两个结合起来可以根据名字和类型注入,等同于 @Resource


  1. @Autowired 与 @Resource 都可以用来装配 bean. 都可以写在字段上,或写在 setter 方法上。

  2. @Autowired 默认按类型装配(byType),默认情况下必须要求依赖对象必须存在,如果要允许 null 值,可以设置它的 required 属性为 false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合 @Qualifier 注解进行使用(@Autowired () @Qualifier ( "xxx" )功能同@Resource),如下:


@Autowired


@Qualifier ( "userDao" )


private UserDao userDao;


  1. @Resource 默认按照名称进行装配(byName),名称可以通过 name 属性进行指定,如果没有指定 name 属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在 setter 方法上默认取属性名进行装配。当找不到与名称匹配的 bean 时才按照类型进行装配。如果name属性一旦指定,就只会按照名称进行装配


@Resource (name= "baseDao" )


private BaseDao baseDao;


总结如下


  • @


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


Autowired 默认按 byType 自动装配,而 @Resource 默认 byName 自动装配。


  • @Autowired 只包含一个参数:required,表示是否开启自动注入,默认是 true。而 @Resource 包含七个参数,其中最重要的两个参数是:name 和 type。

  • @Autowired 如果要使用 byName,需要使用 @Qualifier 一起配合。而 @Resource 如果指定了 name,则用 byName 自动装配,如果指定了 type,则用 byType 自动装配。

  • @Autowired 能够用在:构造器、方法、参数、成员变量和注解上,而 @Resource 能用在:类、成员变量和方法上。

  • @Autowired 是 spring 定义的注解,而 @Resource 是 JSR-250 定义的注解。





课间休息,又来秀一下来自咱们群里同学的搬砖工地,坐标:大连


作者:Onlooker

评论

发布
暂无评论
Java岗大厂面试百日冲刺 - 日积月累,每日三题【Day26】—