spring ioc源码剖析

spring ioc源码剖析

  • ioc的定义
  • IOC核心类与类关系
    • BeanDifinition:如何定义一个bean
    • BeanDefinitionRegistry:注册bean定义的接口
    • AnnotationConfigApplicationContext
    • GenericApplicationContext与BeanFactory
    • AbstractApplicationContext
  • ioc容器的源码实现
    • 后置处理器分类
    • Spring ioc的扫描与注册BeanDefinition
      • BeanDefinitionRegistryPostProcessor与ConfigurationClassPostProcessor
    • Spring ioc -- bean的生命周期管理
      • 后置处理器
        • InstantiationAwareBeanPostProcessor
        • ApplicationContextAwareProcessor
      • bean的完整创建流程
  • 总结

原创不易,转载请注明出处

ioc的定义

全文是Inversion of Control。翻译过来就是控制反转,意思是对象之间的关系不再由传统的程序来控制,而是由spring容器来统一控制这些对象创建、协调、销毁,而对象只需要完成业务逻辑即可。

可以看出ioc主要是通过spring容器来维护bean的生命周期(从创建到销毁),同时也会包含DI(注入依赖)等bean对象填充的操作。接下来我们重点通过源码来看下bean是如何被定义,被创建,以及初始化和销毁的。

我们先抛开spring代码实现,自己思考几分钟;如果让你去做个spring容器的话,有哪些事你肯定是要做的。

  1. Bean的扫描与注册: 加载javaconfig配置类文件,解析它的扫描包(componentScan),安装扫描包递归解析,最后存放到一个配置类集合里。
  2. 创建与管理Bean:拿出配置类集合,进行实例化,属性填充(@Autowire等),以及初始化。

IOC核心类与类关系

在我们跟源码之前,我觉得有必要先写一下关于Spring的IOC的核心类以及它的关系图是怎样的,这样可以让我们对spring有个更上层面和清晰的了解。

BeanDifinition:如何定义一个bean

spring ioc源码剖析_第1张图片
BeanDefinition包含了如下信息:

  • bean的scope,是单例还是prototype,默认是单例
  • bean的dependens,它决定后面创建bean(AbstractApplicationContext.getBean)的时候会优先创建它需要依赖的bean
  • bean有没有被其它的bean通过autowire注解引入,isAutowireCandidate
  • 集合autowire注解的primary注解,isPrimary
  • bean如果是个FactoryBean(FactoryBean与BeanFactory差老远了,前者只是用来修饰bean的实例化方式的),还需要有它的fatoryBeanMethod
  • bean是否是懒加载,默认不是懒加载

BeanDefinitionRegistry:注册bean定义的接口

spring ioc源码剖析_第2张图片
这里有个重要的方法 注册一个bean定义:

registerBeanDefinition(String beanName, BeanDefinition beanDefinition)

AnnotationConfigApplicationContext

我们先启动一个Spring容器

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);

@Configuration
@ComponentScan(basePackages = {"com.yan.ioc.service"})
public class MainConfig {
	@Bean
	public ConfigBean configBeanA() {
		return new ConfigBean();
	}

	@Bean
	public ConfigBean configBeanB() {
		return configBeanA();
	}
}

AnnotationConfigApplicationContext是Spring提供给我们管理ioc容器直接调用的入口类,传入的参数为我们javaconfig配置类的class。

它负责了Bean的注册以及生命周期的管理,同时它还包括了国际化,事件管理等其它的功能。之于它为什么可以完成这么多的事,我们不妨先看看它到底继承了哪些重要的类。

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry

GenericApplicationContext与BeanFactory

首先看到AnnotationConfigApplicationContext的继承了GenericApplicationContext

GenericApplicationContext:Spring对configurableeListableBeanfactory的默认实现和BeanDefinitionRegistry接口:一个成熟的bean工厂基于bean定义元数据,可通过后处理器扩展。

spring ioc源码剖析_第3张图片

GenericApplicationContext实现了BeanDefinitionRegistry bean定义注册接口,那它是如何实现的呢。

它用到了装饰模式,并在装饰模式里new了DefaultListableBeanFactory,而DefaultListableBeanFactory才是真正做到实现BeanDefinitionRegistry接口的类。

public GenericApplicationContext() {
		/**
		 AnnotationConfigApplicationContext被new的同时,因为它是父类,
		 它直接创建了个DefaultListableBeanFactory,这个玩意是不是很眼熟
		 对它就是我们经常说到或者用到的BeanFactory了!!!
		 */
		this.beanFactory = new DefaultListableBeanFactory();
	}

我们再看看DefaultListableBeanFactory的结构
spring ioc源码剖析_第4张图片
从图中可以看到DefaultListableBeanFactory是个非常底层的类了,也是一个具有强大功能的类,它也是我们通常说的BeanFactory。
spring ioc源码剖析_第5张图片
我们直接在DefaultListableBeanFactory类了发现了beanDefinitionMap这个集合,貌似是用来存放BeanDifiniton的,key应该是beanName; 这里我们完全可以做一个大胆的假设,spring扫描javaconfig配置类后,解析出来的所以bean定义信息全部都存放在这里了。

通过DefaultListableBeanFactory的关系图,我们还知道它继承了AbstractApplicationContext

AbstractApplicationContext

springframework.context的抽象实现ApplicationContext接口。不强制配置使用的存储类型;简单地实现公共上下文功能。使用模板方法设计模式,需要具体的子类来实现抽象方法。

它是一个模板类,换句话说它定义了很多方法,我们都是可以直接用的(而且是经常会用到的);只不过它可能会抛出来几个抽象的钩子方法让子类去实现。那我们来看看它到底有那些你一定见过的方法呢。
spring ioc源码剖析_第6张图片
大家一直说refresh方法,那refresh方法到底在哪里呢,它在AbstractApplicationContext这个模板类里;基本上我们对javaconfig配置类的解析,bean的扫描,注册以及实例化,属性填充,初始化都是在这里完成,当然国际化,事件管理也在这里实现的。

那这个模板类有留出了个什么钩子方法呢?

public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

看到上面代码就明白了,GenericApplicationContext装饰了实现了BeanDefinitionRegistry接口的DefaultListableBeanFactory类;然后它又继承了模板类AbstractApplicationContext,把DefaultListableBeanFactory这个又回调给了AbstractApplicationContext。

ioc容器的源码实现

核心类与结构我们大致清晰了,那我们再回到AnnotationConfigApplicationContext类来。如果spring要做ioc容器管理,最起码要做两件事情。

  1. Bean的扫描与注册: 加载javaconfig配置类文件,解析它的扫描包(componentScan),安装扫描包递归解析,最后存放到一个配置类集合里。

  2. 创建与管理Bean:拿出配置类集合,进行实例化,属性填充(@Autowire等),以及初始化。
     
     

这里我画了个Spring ioc容器实现原理的脑图,看不清的可以到processon上创建的项目里去看,密码:Phn3
spring ioc源码剖析_第7张图片

其实如果你对spring里各种后置处理器很了解的话,我想直接看这个脑图是没有问题的。如果没有深入了解也没关系,接下来我将拿几个核心的后置处理器进行讲解。

后置处理器分类

后置处理器主要分两大类:

  1. 注册和修改Bean相关的后置处理器(BeanDefinitionRegistryPostProcessor,和BeanFactoryPostProcessor)
  2. 对Bean进行实例化或初始化时,进行额外操作的后置处理器 (InstantiationAwareBeanPostProcessor, BeanPostPrecessor)
    BeanPostPrecessor主要用于对Bean初始化前后的处理。而InstantiationAwareBeanPostProcessor是继承了BeanPostPrecessor,它同时添加了对Bean实例化前后处理的方法。

Spring ioc的扫描与注册BeanDefinition

再讲解后置处理器之前,还是有必要先说下spring的一个重要思想,不然你自己再去跟源码可能会晕乎乎的。

spring万物皆bean

  1. spring处理任何的流程,一定是通过bean来做的
  2. 如果想处理这个流程,但是没有对应的bean的话,那你必须先注册到容器里面去
  3. 各种后置处理器也是一种bean
     
     

BeanDefinitionRegistryPostProcessor与ConfigurationClassPostProcessor

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor 
  • BeanDefinitionRegistryPostProcessor主要的目的是注册Bean定义
    在这里插入图片描述

  • BeanDefinitionRegistryPostProcessor同时继承了BeanFactoryPostProcesser接口,BeanFactoryPostProcesser的主要目的是修改Bean定义,所以BeanDefinitionRegistryPostProcessor通知具备注册和修改Bean定义的功能。
    在这里插入图片描述

  • ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor,并且Spring将它注册到了容器里。ConfigurationClassPostProcessor这个类非常重要,我们先把流程理清楚。

  • 为什么我们直接通过AnnotationConfigApplicationContext就能把ConfigurationClassPostProcessor注册到容器里呢。(可以参考GenericApplicationContext与BeanFactory小节同时理解)
    spring ioc源码剖析_第8张图片

  • 我们首先要扫描Bean呀,不扫描哪来的注册呢?ConfigurationClassPostProcessor就起到了扫描与注册Bean的关键作用,下面这张图诠释了ioc扫描与注册容器的过程。
    spring ioc源码剖析_第9张图片

Spring ioc – bean的生命周期管理

Bean的生命周期大概分为这四大步,但是Spring又分别在其中加入了后置后处理器的处理。 它的整个过程是发生在**refresh()**方法里。

  1. bean的实例化
  2. bean的属性填充
  3. bean的初始化
  4. bean的销毁

后置处理器

在Spring ioc的扫描与注册里,我们已经知晓了两个后置处理器,分别是BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor ,它们主要是负责BeanDefinition的注册与修改,而在真正创建一个bean的时候,它又用到了如下几大类后置处理器

InstantiationAwareBeanPostProcessor

直接看名字,前缀是Instantiation,那一定是用在实例化的环节来使用。InstantiationAwareBeanPostProcessor继承了BeanPostProcessor, 所有这个接口处理实例化前后做处理,还有在初始化前后做处理的功能。比如AspectJAwareAdvisorAutoProxyCreator后置处理器就实现了InstantiationAwareBeanPostProcessor的接口。

spring容器在getBean去创建一个bean的时候,会去检查容器里是否有实现了InstantiationAwareBeanPostProcessor的注册bean,如果有的化则拿出来在其它bean的实例化前后其执行。

它有如下方法:

  • postProcessBeforeInstantiation(Class beanClass, String beanName)

    这个方法在实例化前处理,一般用于解析指定bean是否有切面,并缓存。

  • postProcessAfterInstantiation(Object bean, String beanName)

    spring 留给我们的扩展接口:让用户可以自定义属性注入,若返回false,后面的一些的后置处理都不存在了,直接返回Bean

  • postProcessPropertyValues(
    PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)

    比如AutowiredAnnotationBeanPostProcessor就实现了它,在属性填充的过程来完成bean的依赖注入。

ApplicationContextAwareProcessor

ApplicationContextAwareProcessor实现了BeanPostProcessor,这个后置处理器主要用来给各种的aware传值

  • EnvironmentAware
  • EmbeddedValueResolverAware
  • ResourceLoaderAware
  • ApplicationEventPublisherAware
  • MessageSourceAware
  • ApplicationContextAware

如果你设计的Bean实现了如上6个Aware,spring会调用ApplicationContextAwareProcessor.postProcessBeforeInitialization把对应aware想要的对象set进去。

bean的完整创建流程

spring ioc源码剖析_第10张图片

总结

  1. spring ioc的流程大致可以分为两块,bean的扫描与注册,bean的创建

  2. spring所有的功能实现的前提是:你把实现该功能的bean注册进来再说

  3. ConfigurationClassPostProcessor是出来扫描和注册的关键bean,它会去解析配置类的@ComponentScan,@Import,然后扫描这些bean,打包成BeanDefiniton并注册到容器里。注意它并没有创建bean,只是注册到了容器里。

  4. bean是通过BeanDefiniton类注册,BeanDefiniton定义的类的class,scope,primary,depends,isAutowire等。

  5. bean的创建可以分为实例化,填充属性,初始化,销毁等阶段。只不过Spring在其中添加了一些后置处理器和aware
    创建过程的后置处理器是实现了BeanPostProcessor接口的类,BeanPostProcessor分别提供初始化前和后的方法。

    比如ApplicationContextAwareProcessor就实现了BeanPostProcessor接口,它主要用于初始化的前处理,把各种aware想要的对象set进去

    而InstantiationAwareBeanPostProcessor继承了BeanPostProcessor,它同时为bean的实例化前后添加了方法。比如AutowiredAnnotationBeanPostProcessor就实现了它,主要用它的实例化后处理的方法来实现bean的依赖注入。

  6. ApplitionContext装饰了BeanFactory,它相比BeanFactory多了国际化的支持,消息的处理,以及事件发布与监听的管理

  7. BeanFactory和FactoryBean是两码子事,FactoryBean是用来修饰这个bean的实例化方法,它是一个工厂设计模式,通过getObject()的方法来返回实例。BeanFactory是来做bean的注册与创建的容器,高级多了。

你可能感兴趣的:(spring,spring,ioc,源码,设计模式,java)