【spring源码】二、bean定义、工厂

一、基础概念

1、IoC 和 DI

IoC (Inversion of Control),即控制反转。这不是一种新的技术,而是 Spring 的一种设计思想。

在传统的程序设计,我们直接在对象内部通过 new 来创建对象,是程序主动去创建依赖对象;而在 Spring 中有专门的一个容器来创建和管理这些对象,并将对象依赖的其他对象注入到该对象中,这个容器我们一般称为 IoC 容器。

所有的类的创建、销毁都由 Spring 来控制,也就是说控制对象生存周期的不再是引用它的对象,而是 Spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被 Spring 控制,所以这叫控制反转。

DI(Dependency Injection),即依赖注入,由 Martin Fowler 提出。可以认为 IoC 和 DI 其实是同一个概念的不同角度描述。

依赖注入是指组件之间的依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。

通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

2、bean

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

大白话:bean 可以认为是那些我们想注入到 Spring IoC 容器的 Java 对象实例的抽象。

我们经常会在 Service 上使用 @Service 注解,然后在要使用该 Service 的类中通过 @Autowire 注解来注入,这个 Service 就是一个 bean。在这个地方,@Service 注解相当于告诉 IoC 容器:这个类你需要帮我创建和管理;而 @Autowire 注解相当于告诉 IoC 容器:我需要依赖这个类,你需要帮我注入进来。

3、BeanDefinition

理解了 bean,BeanDefinition 就好理解了。BeanDefinition 是 bean 的定义,用来存储 bean 的所有属性方法定义。

4、BeanFactory 和 ApplicationContext

BeanFactory:基础类型 IoC 容器,提供完整的 IoC 服务支持。

ApplicationContext:BeanFactory 的子接口,在 BeanFactory 的基础上构建,是相对比较高级的 IoC 容器实现。包含 BeanFactory 的所有功能,还提供了其他高级的特性,比如:事件发布、国际化信息支持、统一资源加载策略等。正常情况下,我们都是使用的 ApplicationContext。

5、FactoryBean

一般情况下,我们将 bean 的创建和管理都交给 Spring IoC 容器,Spring 会利用 bean 的 class 属性指定的类来实例化 bean。

但是如果我们想自己实现 bean 的创建操作,可以实现吗?答案是可以的,FactoryBean 就可以实现这个需求。

FactoryBean 是一种特殊的 bean,它是个工厂 bean,可以自己创建 bean 实例,如果一个类实现了 FactoryBean 接口,则该类可以自己定义创建实例对象的方法,只需要实现它的 getObject() 方法即可。

FactoryBean 可能对于普通开发来说基本用不到也没去注意过,但是它其实应用的非常广,特别是在中间件中,如果你看过一些中间件的源码,一定会看到 FactoryBean 的身影。

二、bean定义

详解请参考:https://blog.csdn.net/java_lyvee/article/details/102633067

bean定义部分都是参考上面链接的,bean定义好理解,bean定义是什么时候创建的确实初学有些难懂,是依赖工厂后置处理器完成的,即ConfigurationClassPostProcessor(工厂后置处理器的实现类)

"bean定义"是什么?

BeanDefintion

可以理解为我们xml文件或者我们注解的那些bean,只不过这些bean还没被创建。

bean定义包含比如类的类型(class),比如类的名字,类的构造方法,还有scope,lazy,dependsOn等等信息需要存储

当然spring容器中不只有我们定义的bean定义,还有预定义好的几个bean定义。

所以流程是BeanDefinitionReader读取xml文件得到bean data,使用bean data去进行实例化。

至于bean定义是怎么装入的,下篇讲

三、bean工厂

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    
    
    this();//实例化了一个beanFactory
    this.register(annotatedClasses);
    this.refresh();
}

1、Spring中的BeanFactory

1.1、BeanFactory类视图

image-20200920135912702

1 2
  1. ApplicationContext 继承了 ListableBeanFactory,这个 Listable 的意思就是,通过这个接口,我们可以获取多个 Bean,最顶层 BeanFactory 接口的方法都是获取单个 Bean 的。
  2. ApplicationContext 继承了 HierarchicalBeanFactory,Hierarchical 单词本身已经能说明问题了,也就是说我们可以在应用中起多个 BeanFactory,然后可以将各个 BeanFactory 设置为父子关系。
  3. AutowireCapableBeanFactory 这个名字中的 Autowire 大家都非常熟悉,它就是用来自动装配 Bean 用的,但是仔细看上图,ApplicationContext 并没有继承它,不过不用担心,不使用继承,不代表不可以使用组合,如果你看到 ApplicationContext 接口定义中的最后一个方法 getAutowireCapableBeanFactory() 就知道了。
  4. ConfigurableListableBeanFactory 也是一个特殊的接口,看图,特殊之处在于它继承了第二层所有的三个接口,而 ApplicationContext 没有。这点之后会用到。

1.2 、工厂详解

1.2.1、BeanFactory

BeanFactory 中定义的各种方法如上面方法注释,整个设计还是比较简洁、直观的,其中将近一半是获取 bean 对象的各种方法,另外就是对 bean 属性的获取和判定,该接口仅仅是定义了 IoC 容器的最基本基本形式,具体实现都交由子类来实现。

1.2.2 、HierarchicalBeanFactory

HierarchicalBeanFactory 译为中文是“分层的”,它相对于 BeanFactory 增加了对父BeanFactory 的获取,子容器可以通过接口方法访问父容器,让容器的设计具备了层次性。这种层次性增强了容器的扩展性和灵活性,我们可以通过编程的方式为一个已有的容器添加一个或多个子容器,从而实现一些特殊功能。层次容器有一个特点就是子容器对于父容器来说是透明的,而子容器则能感知到父容器的存在。典型的应用场景就是 Spring MVC,控制层的 bean 位于子容器中,并将业务层和持久层的 bean 所在的容器设置为父容器,这样的设计可以让控制层的 bean 访问业务层和持久层的 bean,反之则不行,从而在容器层面对三层软件结构设计提供支持。

1.2.3 、ListableBeanFactory

ListableBeanFactory 引入了获取容器中 bean 的配置信息的若干方法,比如获取容器中 bean 的个数,获取容器中所有 bean 的名称列表,按照目标类型获取 bean 名称,以及检查容器中是否包含指定名称的 bean 等等。Listable 中文译为“可列举的”,对于容器而言,bean 的定义和属性是可以列举的对象。

1.2.4 、AutowireCapableBeanFactory

AutowireCapableBeanFactory 提供了创建 bean、自动注入,初始化以及应用 bean 的后置处理器等功能。自动注入让配置变得更加简单,也让注解配置成为可能,Spring 提供了四种自动注入类型:

  • byName:根据名称自动装配。假设 bean A 有一个名为 b 的属性,如果容器中刚好存在一个 bean的名称为 b,则将该 bean 装配给 bean A 的 b 属性。
  • byType: 根据类型自动匹配。假设 bean A 有一个类型为 B 的属性,如果容器中刚好有一个 B 类型的 bean,则使用该 bean 装配 A 的对应属性。
  • constructor:仅针对构造方法注入而言,类似于 byType。如果 bean A 有一个构造方法,构造方法包含一个 B 类型的入参,如果容器中有一个 B 类型的 bean,则使用该 bean 作为入参,如果找不到,则抛出异常。
  • autodetect:根据 bean 的自省机制决定采用 byType 还是 constructor 进行自动装配。如果bean 提供了默认的构造函数,则采用 byType,否则采constructor。

总结:
<beans/> 元素标签中的 default-autowire 属性可以配置全局自动匹配,default-autowire 默认值为 no,表示不启用自动装配。在实际开发中,XML 配置方 式很少启用自动装配功能,而基于注解的配置方式默认采用 byType 自动装配策略。

1.2.5 、ConfigurableBeanFactory

ConfigurableBeanFactory 提供配置 Factory 的各种方法,增强了容器的可定制性,定义了设置类装载器、属性编辑器、容器初始化后置处理器等方法。

1.2.6 、DefaultListableBeanFactory

DefaultListableBeanFactory 是一个非常重要的类,它包含了 IoC 容器所应该具备的重要功能,是容器完整功能的一个基本实现,XmlBeanFactory 是一个典型的由该类派生出来的 Factory,并且只是增加了加载 XML 配置资源的逻辑,而容器相关的特性则全部由 DefaultListableBeanFactory 来实现

1.2.7 、ApplicationContext

ApplicationContext 是 Spring 为开发者提供的高级容器形式,也是我们初始化 Spring 容器的常用方式,除了简单容器所具备的功能外,ApplicationContext 还提供了许多额外功能来降低开发人员的开发量,提升框架的使用效率。这些额外的功能主要包括:

  • 国际化支持:ApplicationContext 实现了 org.springframework.context.MessageSource接口,该接口为容器提供国际化消息访问功能,支持具备多语言版本需求的应用开发,并提供了多种实现来简化国际化资源文件的装载和获取。
  • 发布应用上下文事件:ApplicationContext 实现了org.springframework.context.ApplicationEventPublisher 接口,该接口让容器拥有发布应用上下文事件的功能,包括容器启动、关闭事件等,如果一个 bean 需要接收容器事件,则只需要实现ApplicationListener 接口即可,Spring 会自动扫描对应的监听器配置,并注册成为主题的观察者。
  • 丰富的资源获取的方式:ApplicationContext 实现了org.springframework.core.io.support.ResourcePatternResolver 接口,ResourcePatternResolver 的实现类 PathMatchingResourcePatternResolver 让我们可以采用Ant 风格的资源路径去加载配置文件。
1.2.8 、ConfigurableApplicationContext

ConfigurableApplicationContext 中主要增加了 refresh 和 close 两个方法,从而为应用上下文提供了启动、刷新和关闭的能力。其中 refresh 方法是高级容器的核心方法,方法中概括了高级容器初始化的主要流程(包含简单的容器的全部功能,以及高级容器特有的扩展功能)

1.2.9 、WebApplicationContext

WebApplicationContext 是为 WEB 应用定制的上下文,可以基于 WEB 容器来实现配置文件的加载,以及初始化工作。对于非 WEB 应用而言,bean 只有 singleton 和 prototype 两种作用域,而在WebApplicationContext 中则新增了 request、session、globalSession,以及 application四种作用域。

WebApplicationContext 将整个应用上下文对象以属性的形式放置到 ServletContext 中,所以在WEB 应用中,我们可以通过 WebApplicationContextUtils 的getWebApplicationContext(ServletContext sc) 方法,从 ServletContext 中获取到ApplicationContext 实例。为了支持这一特性,WebApplicationContext 定义了一个常量:ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() +".ROOT"。并在初始化应用上下文时以该常量为 key,将 WebApplicationContext 实例存放到 ServletContext的属性列表中,当我们在调用WebApplicationContextUtils 的getWebApplicationContext(ServletContext sc) 方法时,本质上是在调用 ServletContext 的getAttribute(String name) 方法,只不过 Spring 会对获取的结果做一些校验。

1.2.10 、高级容器的一些具体实现类型
  • AnnotationConfigApplicationContext:是基于注解驱动开发的高级容器类,该类中提供了AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner两个成员,AnnotatedBeanDefinitionReader用于读取注解创建Bean的定义信息,ClassPathBeanDefinitionScanner负责扫描指定包获取Bean的定义信息。
  • ClasspathXmlApplicationContext:是基于xml配置的高级容器类,它用于加载类路径下配置文件。
  • FileSystemXmlApplicationContext:是基于xml配置的高级容器类,它用于加载文件系统中的配置文件。
  • AnnotationConfigWebApplicationContext:是注解驱动开发web应用的高级容器类。

后置处理器

  • 在创建对象之前
  • 容器初始化之前
  • BeanPostProcessor
  • BeanFactoryPostProcessor:根据环境变量对工厂对象进行修改
  • BeanFacory
  • FactoryBean普通对象,只是生产bean的,工厂里面另一个工厂,程序员自己写的工厂,生产的模子,getObject()
  • 运行期增强
  • 编译期增强ApectJ、lombok
  • 载入期增强

猜你喜欢

转载自blog.csdn.net/hancoder/article/details/111410583