首页 > 编程语言 > 详细

《精通Spring4.x企业应用开发实战》第六章

时间:2020-11-18 19:16:58      阅读:35      评论:0      收藏:0      [点我收藏+]

  Spring容器就像一台构造精妙的机器,我们通过配置文件向机器传达控制信息,机器就能够按照设定的模式工作。如果将Spring 容器比作一辆汽车,那么可以将BeanFactory看成汽车的发动机,而ApplicationContext则是一辆完整的汽车,它不但包括发动机,还包括离合器、变速器及底盘、车身、电气设备等其他组件。在ApplicationContext内,各个组件按部就班、有条不紊地完成汽车的各项功能。

 

6.1.1内部工作机制

  Spring 的 AbstractApplicationContext是 ApplicationContext的抽象实现类,该抽象类的refresh()方法定义了Spring容器在加载配置文件后的各项处理过程,这些处理过程清晰地刻画了Spring容器启动时所执行的各项操作。下面来看一下refresh()内部定义了哪些执行逻辑,如代码所示。

  技术分享图片

 

   

  (1)初始化 BeanFactory:根据配置文件实例化 BeanFactory,在 obtainFreshBeanFactory()方法中,首先调用refreshBeanFactory()方法刷新 BeanFactory,然后调用getBeanFactory()方法获取 BeanFactory,这两个方法都是由具体子类实现的。在这一步里,Spring 将配置文件的信息装入容器的Bean定义注册表(BeanDefinitionRegistry)中,但此时 Bean还未初始化。

  (2)调用工厂后处理器:根据反射机制从 BeanDefinitionRegistry中找出所有实现了BeanFactoryPostProcessor接口的 Bean,并调用其postProcessBeanFactory()接口方法。

  (3)注册 Bean后处理器:根据反射机制从 BeanDefinitionRegistry中找出所有实现了BeanPostProcessor接口的 Bean,并将它们注册到容器Bean后处理器的注册表中。

  (4)初始化消息源:初始化容器的国际化消息资源  

  (5)初始化应用上下文事件广播器。  

  (6)初始化其他特殊的 Bean:这是一个钩子方法,子类可以借助这个方法执行一些特殊的操作,如 AbstractRefreshableWebApplicationContext就使用该方法执行初始化ThemeSource的操作。  

  (7)注册事件监听器。  

  (8)初始化所有单实例的 Bean,使用懒加载模式的Bean 除外:初始化 Bean后,将它们放入 Spring容器的缓存池中。

 

  技术分享图片

  • 1、ResourceLoader从存储介质中加载Spring配置信息,并使用Resource表示这个配置文件的资源;
  • 2、BeanDefinitionReader读取Resource所指向的配置文件资源,然后解析配置文件。配置文件中每一个<bean>解析成一个BeanDefinition对象,并保存到BeanDefinitionRegistry中;
  • 3、容器扫描BeanDefinitionRegistry中的BeanDefinition,使用Java的反射机制自动识别出Bean工厂后处理后器(实现BeanFactoryPostProcessor接口)的Bean,然后调用这些Bean工厂后处理器对BeanDefinitionRegistry中的BeanDefinition进行加工处理。主要完成以下两项工作:
    • 1)对使用到占位符的<bean>元素标签进行解析,得到最终的配置值,这意味对一些半成品式的BeanDefinition对象进行加工处理并得到成品的BeanDefinition对象;
    • 2)对BeanDefinitionRegistry中的BeanDefinition进行扫描,通过Java反射机制找出所有属性编辑器的Bean(实现java.beans.PropertyEditor接口的Bean),并自动将它们注册到Spring容器的属性编辑器注册表中(PropertyEditorRegistry);
  • 4.Spring容器从BeanDefinitionRegistry中取出加工后的BeanDefinition,并调用InstantiationStrategy着手进行Bean实例化的工作;
  • 5.在实例化Bean时,Spring容器使用BeanWrapper对Bean进行封装,BeanWrapper提供了很多以Java反射机制操作Bean的方法,它将结合该Bean的BeanDefinition以及容器中属性编辑器,完成Bean属性的设置工作;
  • 6.利用容器中注册的Bean后处理器(实现BeanPostProcessor接口的Bean)对已经完成属性设置工作的Bean进行后续加工,直接装配出一个准备就绪的Bean。

 6.1.2BeanDefinition

  Spring通过BeanDefinition将配置文件中的<bean>配置信息转换为容器的内部表示,并将这些 BeanDefiniton注册到 BeanDefinitonRegistry 中。Spring容器的BeanDefinitionRegistry就像Spring配置信息的内存数据库,后续操作直接从BeanDefinitionRegistry中读取配置信息。一般情况下,BeanDefinition只在容器启动时加载并解析,除非容器刷新或重启,这些信息不会发生变化。当然,如果用户有特殊的需求,也可以通过编程的方式在运行期调整BeanDefinition的定义。
创建最终的 BeanDefinition主要包括两个步骤。
  (1)利用 BeanDefinitionReader读取承载配置信息的Resource,通过XML解析器解析配置信息的DOM对象,简单地为每个<bean>生成对应的 BeanDefinition对象。但是这里生成的 BeanDefinition可能是半成品,因为在配置文件中,可能通过占位符变量引用外部属性文件的属性,这些占位符变量在这一步里还没有被解析出来。
  (2)利用容器中注册的 BeanFactoryPostProcessor对半成品的BeanDefinition进行加工处理,将以占位符表示的配置解析为最终的实际值,这样半成品的 BeanDefinition就成为成品的 BeanDefinition.

 

6.1.3InstantiationStrategy

  InstantiationStrategy仅负责实例化 Bean的操作,相当于执行Java语言中new 的功能,它并不会参与Bean属性的设置工作。所以由InstantiationStrategy返回的Bean 实例实际上是一个半成品的 Bean实例,属性填充的工作留待BeanWrapper来完成。

 

6.1.4BeanWrapper

  要顺利地填充 Bean属性,除了目标 Bean实例和属性编辑器外,还需要获取 Bean对应的 BeanDefinition,它从 Spring容器的 BeanDefinitionRegistry中直接获取。Spring主控程序从 BeanDefinition中获取 Bean属性的配置信息PropertyValue,并使用属性编辑器对PropertyValue进行转换以得到 Bean的属性值。对 Bean 的其他属性重复这样的步骤,就可以完成 Bean所有属性的注入工作。BeanWrapperImpl在内部使用Spring 的BeanUtils 工具类对Bean进行反射操作,设置属性。下一节将详细介绍属性编辑器的原理,并讲解如何通过配置的方式注册自定义的属性编辑器。

 

6.2属性编辑器

  在Spring 配置文件里,往往通过字面值为 Bean各种类型的属性提供设置值:不管是double类型还是 int类型,在配置文件中都对应字符串类型的字面值。BeanWrapper在填充Bean属性时如何将这个字面值正确地转换为对应的double或int等内部类型呢?我们可以隐约地感觉到一定有一个转换器在“暗中相助”,这个转换器就是属性编辑器。

  “属性编辑器”这个名字可能会让人误以为是一个带用户界面的输入器,其实属性编辑器不一定非得有用户界面,任何实现java.beans.PropertyEditor接口的类都是属性编辑器。属性编辑器的主要功能就是将外部的设置值转换为JVM内部的对应类型,所以属性编辑器其实就是一个类型转换器。

  PropertyEditor是 JavaBean规范定义的接口,JavaBean规范中还有其他一些PropertyEditor配置的接口。为了彻底地理解属性编辑器,必须对JavaBean中有关属性编辑器的规范进行学习,相信这些知识对学习和掌握Spring中的属性编辑器会大有帮助。

 

在基于XML的配置文件中,通过“${propName}”形式引用属性值。类似的,基于注解配置的 Bean可以通过@Value注解为 Bean 的成员变量或方法入参自动注入容器已有的属性,如下:

  技术分享图片

  @Value注解可以为 Bean注入一个字面值,也可以通过@Value("S propName}")的形式根据属性名注入属性值。由于标注@Configuration的类本身就相当标注了@Component,所以在标注@Configuration的类中引用属性的方式和基于注解配置的引用方式是完全一样的,此处不再赘述。使用@Value注解来引用属性值带来很大的便利,但在使用过程中,一定要确保所引用的属性值在属性文件中已经存在且数值匹配,否则会造成Bean创建错误,引发意想不到的异常。

   

  这里放一个解释@Autowired和@Value的博客,我看到这里的时候是对这个问题产生了疑惑的:

  https://www.cnblogs.com/yichunguo/p/12110755.html

 

  Spring既允许在 Bean定义中通过$ {propName}引用属性值,也允许在属性文件中使用${propName}实现属性之间的相互引用。

  技术分享图片

 

 

  参考:

  https://www.cnblogs.com/yichunguo/p/12110755.html

  

《精通Spring4.x企业应用开发实战》第六章

原文:https://www.cnblogs.com/hellostranger/p/14000238.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!