SpringFramework源码分析(1):Spring容器中的核心组件与层次

Spring的IoC容器

Spring的IoC容器是Spring的核心,IOC(Inversion of Control )控制反转的。IoC和DI(Dependency Injection)是一个意思,也就是说对象定义它们的依赖(也就是和它们一起干活的其他对象),Spring容器会把这些依赖给注入进去。具体来讲,我们可以通过xml文件、注解和java代码的形式来定义对象和它们之间的依赖,Spring会自动帮我们把它们解析成BeanDefinition、注册BeanDefinition,然后将BeanDefinition实例化,填充属性并注入依赖,调用生命周期方法等,最终生成Bean,从而供用户使用。

Spring容器的工作原理

我们有一些POJO(示例代码中的A和B),还有一些配置信息,这些配置信息可以是xml文件、注解、java代码(示例代码中的AppConfig类)。我们把这两坨扔给Spring容器(示例代码中的AnnotationConfigApplicationContext),Spring容器帮我们实例化并装配好,我们使用时直接从Spring获取即可,例如从Spring容器中获取A实例applicationContext.getBean(A.class)。

public class A {
}

public class B {
}

@Configuration
public class AppConfig {
	@Lazy
	@Bean
	@DependsOn("b")
	public A a() {
		System.out.println("Generate bean a");
		return new A();
	}

	@Scope("prototype")
	@Bean
	public B b() {
		System.out.println("Generate bean b");
		return new B();
	}
}

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext configApplicationContext =
				new AnnotationConfigApplicationContext(AppConfig.class);
		A a = applicationContext.getBean(A.class);
		B b = applicationContext.getBean(B.class);
	}
}

核心概念介绍

那么问题来了,Spring是怎么把我们的POJO变成Spring管理的对象的呢?这里涉及到Spring中的一些概念,包括Bean、BeanDefinition、BeanFactory、ApplicationContext、BeanDefinitionRegistry、SingletonBeanRegistry、BeanDefinitionReader、BeanFactoryPostProcessor、BeanPostProcessor

  • Bean
    我们这里说的Bean是Spring中的Bean,而不是普通的JavaBean。Spring中的Bean是Spring IoC容器管理的对象,Bean不是普通的java对象,Bean具有生命周期,即创建、初始化和销毁。Spring的容器就是用来管理Bean的。

  • BeanDefinition
    在Java中我们使用Class来描述类或接口,但是Class不能描述一个类是否要懒加载、自动装配模式等属性,所以在Spring中使用BeanDefinition来描述Bean实例,BeanDefinition包括Bean属于哪个Class、Bean的Name、Scope、Constructor arguments、Properties、Autowiring mode、Lazy initialization mode、Initialization method、Destruction method。

  • BeanFactory
    BeanFactory是访问Spring Bean容器的最基本的接口,BeanFactory是所有应用组件(ApplicationComponent)的注册中心,为所有的组件提供集中化的配置。BeanFactory接口的实现类需要满足一定要求:
    1 应该持有一系列的BeanDefination,通过BeanDefination,容器可以返回独立的或共享的实例。
    2 应该尽可能地支持标准的Bean生命周期接口,即Bean的初始化、创建和销毁。
    我们可以看到BeanFactory中提供了许多getBean的方法,此外还提供了判断一个Bean是否是单例、原型等方法。

  • ApplicationContext
    ApplicationContext是BeanFactory的扩展,是为一个应用提供配置的中心接口,主要提供以下能力;
    1 通过继承ListableBeanFactory和HierarchicalBeanFactory接口,可以访问BeanFactory中的应用组件(也就是Bean);
    2 通过继承ResourceLoader接口,可以加载资源,例如classPath资源、文件系统资源等;
    3 通过继承ApplicationEventPublisher接口,可以向注册的Listener发布事件;
    4 通过继承MessageSource,可以解析消息,支持国际化;
    5 支持从parent context继承,例如WebApplicationContext。

      public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
      MessageSource, ApplicationEventPublisher, ResourcePatternResolver
    

在这里插入图片描述

  • BeanDefinitionRegistry
    BeanFactory接口只提供了访问Bean的方法,而BeanDefinitionRegistry则提供了注册BeanDefinition的方法。DefaultListableBeanFactory和GenericApplicationContext都实现了BeanDefinitionRegistry接口。

  • SingletonBeanRegistry
    SingletonBeanRegistry接口提供了注册单实例Bean的能力,ConfigurableBeanFactory继承了该接口。
    注意这个接口是用来向Spring容器中添加单实例Bean的,而BeanDefinitionRegistry则是向Spring容器中添加BeanDefinition的。

  • BeanDefinitionReader
    BeanDefinitionReader指定了loadBeanDefinition方法,从而根据传入的String或Resource类型参数加载BeanDefinition。需要注意的是一个BeanDefinition的读取器不必非要实现这个接口,例如AnnotationConfigApplicationContext中的AnnotatedBeanDefinitionReader就没有实现该接口。

  • BeanFactoryPostProcessor
    BeanFactoryPostProcessor是Spring提供的一个扩展点,主要是用来修改ApplicationContext中的BeanDefinition而不是Bean实例。
    BeanFactoryPostProcessor的一个重要的子接口是BeanDefinitionRegistryPostProcessor,BeanDefinitionRegistryPostProcessor允许在BeanFactoryPostProcessor处理BeanDefinition之前注册一些BeanDefinition。
    BeanDefinitionRegistryPostProcessor目前唯一的实现是ConfigurationClassPostProcessor,这个类非常重要,主要是用来处理@Configuration标注的配置类的,它处理@Component、@Import、@Bean等注解,将用户基于注解和java代码定义的类和类之间的依赖关系转化成BeanDefinition。我们会在之后的文章中对ConfigurationClassPostProcessor进行专门的介绍。

  • BeanPostProcessor
    BeanPostProcessor也是Spring提供的一个扩展点,主要是在Bean实例化前后执行回调,我们之后会单独介绍该接口。

接口层次

下面介绍一下BeanDefinition、BeanFactory、ApplicationContext接口的层次。我们可以看到Spring中接口和类的层次是相当复杂的,这是因为Spring把能分开的都分开了,体现了单一职责的原则。子接口或子类可以组合这些接口,从而实现丰富的功能。

BeanDefinition的层次

  • BeanDefinition
    BeanDefinition用来描述Bean实例,包括属性值、构造器参数值以及它的具体实现提供的额外的信息。通过BeanFactoryPostProcessor可以对BeanDefinition的属性值和其他元数据信息进行修改。

  • AnnotatedBeanDefinition
    AnnotatedBeanDefinition是BeanDefinition的直接子接口,主要是可以获取到AnnotationMetadata,AnnotationMetadata接口主要提供对一个类上注解的访问,例如getAnnotationTypes、getAnnotatedMethods等。

  • AbstractBeanDefinition
    AbstractBeanDefinition是实现了BeanDefinition接口的抽象类,提取出了GenericBeanDefinition、RootBeanDefinition以及ChildBeanDefinition的公共属性,例如beanClass、scope、abstractFlag、lazyInit、autowireMode、dependsOn、primary、initMethodName、destroyMethodName等。

  • GenericBeanDefinition
    GenericBeanDefinition是AbstractBeanDefinition的子类,它是BeanDefinition接口的标准实现。通常使用GenericBeanDefinition是为了注册用户可见的BeanDefinition,这些BeanDefinition可能会进一步被PostProcessor处理,也可能被重新设置parentName。Spring 2.5之后,通过编程的方式注册BeanDefinition的推荐方式是使用GenericBeanDefinition,因为可以通过setParentName方法动态地设置父依赖

  • RootBeanDefinition
    RootBeanDefinition代表MergedBeanDefinition,一个RootBeanDefinition可能是由多个有继承关系的BeanDefinition创建而来的,RootBeanDefinition本质上是Spring的BeanFactory运行期间统一的BeanDefinition视图。

  • ChildBeanDefinition
    ChildBeanDefinition使得Bean可以从他的parent继承一些属性,包括构造器参数值、属性值、重载父类方法、init和destroy方法、静态工厂方法。对于depends on、autowire mode、 dependency check、singleton、lazy init则会使用自己设置的值。使用RootBeanDefinition和ChildBeanDefinition可以表达预先确定好的父子关系。

  • ScannedGenericBeanDefinition
    ScannedGenericBeanDefinition是GenericBeanDefinition的子类,使用ASM ClassReader解析.class文件,从而获取到相关的元信息。

  • AnnotatedGenericBeanDefinition
    AnnotatedGenericBeanDefinition也是GenericBeanDefinition的子类,在将@Configuration标注的类(配置类)转化成BeanDefinition时,使用的就是AnnotatedGenericBeanDefinition。

  • ConfigurationClassBeanDefinition
    ConfigurationClassBeanDefinition是ConfigurationClassBeanDefinitionReader的内部类,ConfigurationClassBeanDefinition表示BeanDefinition是从Configuration Class(配置类)中创建的而不是基于其他的配置源。

  • ClassDerivedBeanDefinition
    ClassDerivedBeanDefinition是GenericApplicationContext的内部类,在GenericApplicationContext#registerBean方法中会把beanClass转化成ClassDerivedBeanDefinition。

      ClassDerivedBeanDefinition beanDefinition = new ClassDerivedBeanDefinition(beanClass);
    

在这里插入图片描述

BeanFactory的层次

  • BeanFactory
    BeanFactory接口是Spring IoC容器最基本的接口,主要提供各种getBean的方法,从而可以从Spring容器中获取到Bean。注意,BeanFactory只提供了获取Bean的接口,而没有提供注册Bean的接口。注册Bean的接口是BeanDefinitionRegistry,也就是说注册和获取Bean的接口是隔离的。

  • ListableBeanFactory
    ListableBeanFactory是BeanFactory的直接子接口,主要是提供“批量”的能力,例如批量获取BeanName和Bean实例。

  • HierarchicalBeanFactory
    HierarchicalBeanFactory是BeanFactory的直接子接口,主要提供支持父子容器的能力,即可以获取当前容器的父容器。

  • AutowireCapableBeanFactory
    AutowireCapableBeanFactory是BeanFactory的直接子接口,主要提供自动注入的能力。

  • ConfigurableBeanFactory
    ConfigurableBeanFactory提供配置BeanFactory的一系列方法,包括setBeanClassLoader、addBeanPostProcessor、registerAlias等。

  • ConfigurableListableBeanFactory
    ConfigurableListableBeanFactory除了ConfigurableBeanFactory提供的配置方法,ConfigurableListableBeanFactory还提供分析和改变BeanDefinition、预实例化单实例Bean的方法。

  • AbstractBeanFactory
    AbstractBeanFactory是BeanFactory的抽象基类,提供了基本的实现

  • DefaultListableBeanFactory
    DefaultListableBeanFactory是
    ConfigurableListableBeanFactory和BeanDefinitionRegistry接口的默认实现,在AnnotationConfigApplicationContext中会用到。
    DefaultListableBeanFactory中的beanDefinitionMap就是放BeanDefinition的。

/** Map of bean definition objects, keyed by bean name. */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

在这里插入图片描述

ApplicationContext的层次

  • ApplicationContext
    ApplicationContext是配置一个应用的中心接口。

  • ConfigurableApplicationContext
    ApplicationContext接口中大多数方法都是getBean,ConfigurableApplicationContext则提供了一些设置 applicationContext的方法,例如setXXX addXXX registerXXX等。

  • WebApplicationContext
    WebApplicationContext为web应用提供配置,在ApplicationContext的基础上增加了getServletContext方法,可以获取到标准的javax.servlet.ServletContext。

  • AbstractApplicationContext
    AbstractApplicationContext是ApplicationContext的抽象实现,提供了通用能力,使用模板方法设计模式,使其子类实现一些具体的逻辑。
    ApplicationContext需要检测定义在BeanFactory中的其他Bean,因此AbstractApplicationContext中注册了包括BeanFactoryPostProcessors、BeanPostProcessors以及ApplicationListeners接口的一些实现类对应的Bean

  • GenericApplicationContext
    GenericApplicationContext内部持有一个DefaultListableBeanFactory
    并且没有强制指定BeanDefinition的类型。此外,实现了BeanDefinitionRegistry接口,从而可以注册BeanDefinition。
    其他ApplicationContext的实现在每次调用refresh方法时,会创建一个新的BeanFactory,GenericApplicationContext只能调用refresh方法一次,多次调用会抛异常。另外,我们常用的基于注解的AnnotationConfigApplicationContext是GenericApplicationContext的子类。

      Exception in thread "main" java.lang.IllegalStateException: GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once
    
  • AbstractRefreshableApplicationContext
    AbstractRefreshableApplicationContext支持多次调用refresh方法,每次会创建一个新的BeanFactory实例。AbstractRefreshableApplicationContext的子类需要实现loadBeanDefinitions方法,从而在每次调用refresh方法时可以将BeanDefinition加载到DefaultListableBeanFactory中。

  • AnnotationConfigApplicationContext
    AnnotationConfigApplicationContext支持以@Configuration标注的类、@Component和JSR-330的@Inject注解作为BeanDefinition源,同时也支持直接注册类register(Class…)以及基于classPath扫描scan(String…)的方式注册类。
    如果有多个@Configuration标注的类,那么后面的类中定义的@Bean方法会覆盖前面的类。利用这点可以通过增加额外的@Configuration类来覆盖某些BeanDefinition。

在这里插入图片描述

SpringFramework系列目录

SpringFramework系列目录

猜你喜欢

转载自blog.csdn.net/sodawoods/article/details/107240123