Spring相关面试题(二)

13.Spring IOC容器的加载过程

四个形态

概念态---<Bean信息>---> 定义态----BeanDefinition---->纯净态----DI---->成熟态

对应Bean的生命周期

实例化 --> 属性注入 ---> 实例化

概念态---->定义态

  1. 实例化一个ApplicationContext的对象

  2. 调用bean工厂后置处理器完成扫描;

  3. 循环解析扫描出来的类信息;

  4. 实例化一个BeanDefinition对象来存储解析出来的信息

  5. 把实例化好的beanDefinition对象put到beanDefinitionMap当中缓存起来以便后面实例化bean;

  6. 再次调用其他bean工厂后置处理器

定义态----BeanDefinition---->纯净态

  1. 当然spring还会干很多事情,比如国际化,比如注册BeanPostProcessor等等,如果我们只关心如何实例化一个bean的话那么这一步就是spring调用finishBeanFactoryinitialization方法来实例化单例的bean,实例化之前spring要做验证需要遍历所有扫描出来的类,依次判断这个bean是否Lazy,是否prototype,是否 abstract等等;

  2. 如果验证完成spring在实例化一个bean之前需要推断构造方法,因为spring实例化对象是通过构造方法反射,故而需要知道用哪个构造方法;

  3. 推断完构造方法之后spring调用构造方法反射实例化一个对象;注意我这里说的是对象、对象、对象;这个时候对象已经实例化出来了,但是并不是一个完整的bean,最简单的体现是这个时候实例化出来的对象属性是没有注入,所以不是一个完整的bean;10:spring处理合并后的beanDefinition

纯净态----DI---->成熟态

  1. Spring处理合并的BeanDefinition

  2. 判断是否需要完成属性注入

  3. 如果需要,则开始注入

初始化

  1. 判断bean的类型回调Aware接口。

  2. 调用生命周期回调方法

  3. 如需要代理完成代理

创建完成

  1. 放到单例池中去。

14 Spring Ioc的扩展点

挑重点回答:

  1. BeanFactoryPostProcessor的postProcessBeanFactory方法

  2. BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry

  3. BeanPostProcessor实现类:在Bean的生命周期会调用9次Bean的后置处理器

  4. 初始化阶段回到用很多的Aware接口

  5. 在初始化和销毁中,也会有很多的回调方法。

15 SpringBean和JavaBean

被Spring IOC容器管理的对象都是Bean。

Java的类就是JavaBean

16 配置Bean的方法
  1. XML

  2. 注解:@Component @Service @Controller @Repository,需要配置扫描包,通过反射获得Bean

  3. JavaConfig :@Bean,用在方法上,可以自己控制对象的创建。

  4. @Import : @Import(A.class)

17 单例Bean的优势(单例模式的优势)?

单例:对象只会创建一次。

  1. 减少新的实例创建,减少了服务器性能和内存的消耗

  2. 对象少了,jvm需要回收的对象也就少了。

  3. 可以迅速获得到Bean,Bean除了第一次获得是在内存中,别的时候都是在缓存中获取。

18 Spring的Bean是不是线程安全的?

单例Bean会存在线程安全的问题,如果类中有成员变量,并且有读写操作,就会有线程安全的问题,把成员变量放到方法中就是线程安全的了。

  1. 使用多例解决线程安全问题。

  2. 把成员变量放的ThreadLocal中,ThreadLocal是每个线程独有的。

  3. 加同步锁,加入synchronized。

19 Spring实例化Bean有几种方式
  1. 构造器反射的方式(Spring管理,不能控制)。

  2. 静态工厂方式。

    <xml factory-method="createPersonFactory"/>

    然后回调用这个静态方法去实例Bean

  3. 实例化工厂方式@Bean

    <xml factory-bean="" factory-method=""/>

    @Bean底层就是通过这两个方式进行的。

  4. FactoryBean方式

    实现FactoryBean的getObject方法,在这个方法中返回一个对象,在getObjectType()中获得一个class。

20 Bean的装配,Bean的自动装配 (或者说注入)
  1. 通过XML配置可以装配上

  2. @Autowired或者其他注解,可以自动注入。

21 自动装配的条件
  1. 需要set方法

  2. 任然可以使用<constructor-arg/> 和 <propety/>进行覆盖

  3. 不能装配基本的数据类型

  4. 自动装配不如显示装配精确

23 自动装配的几种方式
  1. no:不进行自动装配,通过ref手动注入

  2. byName:

  3. byType:

  4. constructor:

  5. autodetect:Spring3.0后弃用.

24 Bean有哪些生命周期的回调方法?有哪几种实现方式?

1.初始化方法

  1. 注解方式:@PostConstruct

  2. 实现InitiallizingBean接口

2.销毁方法

1. 注解方式:@PreDestroy
2. 实现DisposableBean接口
3. @Bean(destroyMethod = “destroyMethod”)
25 Spring在加载过程中,有几种形态?
  1. 概念态

    @Bean <Bean/>Bean的配置形态。

  2. 定义态

    BeanDefinition 封装Bean的生产指标。

  3. 纯静态

    二级缓存,早起暴露Bean,循环依赖才能体现纯静态的作用。

  4. 成熟态

    SingletonObjects ,最终在应用使用的Bean

26 Spring是如何帮助我们在并发的情况下避免获取不完整的Bean

什么是不完整的Bean?

实例化之后,没有经过属性赋值。

双重检查锁和二次检查缓存

二个同步锁

再读二级缓存和三级缓存的时候,都有一把锁,如果A线程先进来,会进行Bean的实例化,这其中到放到一级缓存的过程中,都是锁住的,另外一个线程都是堵塞的状态,直到A线程创建完一个对象;但是B线程读的时候,一级缓存是没有加锁的,而且B此时已经读完了一级缓存,结果是null,同时A创建好了一个Bean,二级缓存和三级缓存都清空,B这个时候就得重新创建了吗???不是,在创建Bean之前,B线程也会再次进行getSingleton()的调用,这是就会直接拿到Bean。

为什么一级缓存不加锁呢?

性能问题:如果一个线程创建一个A Bean对象,但是另一线程要拿C Bean对象,这个时候这个线程也是堵塞的。

27 BeanDefinition的加载过程
  1. JavaConfig @Bean

  2. 解析配置类

    1. 读取配置:BeanDefinitionReader

    2. 解析:Config : @Bean @Import @Component

    3. 配置类解析器 ConfigurationClassParser

    4. 扫描:ClassPathBeanDefinitionSacnner # doScan:根据包路径找到所有的.class文件,判断类是不是标准的@Component注解,排除接口,是不是抽象类

    5. 注册BeanDefinition

  3. 注册BeanDefinitionMap

  4. 生产

28 如何在Spring所有Bean创建完后做扩展

哪里才算所有的Bean创建完成:new ApplicationContext() -----> refresh() ------> finishBeanFactoryInitialzation(循环所有的BeanDefinition进行getBeanFactory.getBean()生成所有的Bean) 这个循环之后Bean也就创建完了。

  1. 扩展方式一:基于SmartInitializingSingleton接口,在finishBeanFactoryInitialization(beanFactory); (源码在DefaultListableBeanFactory.java的preInstantiateSingletons()方法中),实现SmartInitializingSingleton接口,可以在所有单例bean全部实例化以后回调

  2. 扩展方式二:在AbstractApplicationContext.java中的finishRefresh()方法中,发布了一个最后的事件,publishEvent(new ContextRefreshedEvent(this));监听事件@EventListener(ContextRefreshedEvent.class)

  • 19
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值