spring最重要的是ioc和aop了,深入spring学习,源码当然必不可少,本文尝试分下spring ioc源码,希望能够对大家深入spring有一定的帮助。

一、AnnotationConfigApplicationContext

spring提供了很多容器,AnnotationConfigApplicationContext是spring提供的一个支持注解式注入的容器,本文从AnnotationConfigApplicationContext容器开始,进行对spring ioc源码探索之旅。

先来分析它的继承关系图,图在下面,已从左至右,从上到下的顺序开始分析,ResourceLoader是一个支持容器从文件系统和类路径加载资源的接口,默认实现是DefaultResourceLoader,ResourcePatternResolver扩展了ResourceLoader接口,能够支持“路径模式”的方式加载资源,也就是路径带*号的,比如说支持/WEB-INF/*-context.xml形式的路径。

MessageSource是支持国际化的接口,ApplicationEventPublisher是spring提供的事件模型,支持发布事件。

BeanFactory是spring的核心接口,是用来访问spring bean的容器,这个接口的实现类会拥有一个bean definitions集合,beanDefinitions是描述spring bean的数据结构。另外spring规定了beanfactory的实现类必须要支持的生命周期接口,也就是spring给我们提供的扩展点,包括BeanNameAware、BeanClassLoaderAware,BeanFactoryAware,EnvironmentAware,EmbeddedValueResolverAware,ResourceLoaderAware,ApplicationEventPublisherAware,BeanPostProcessors等等,关于生命周期接口以后在详细阐述,另外它的扩展接口ListableBeanFactory表示从容器中一次性获取多个spring bean对象。EnviromentCapable是一个暴露容器环境的接口,通过getEnvironment方法,返回当前容器的Environment对象,值得一提的是在ConfigurableApplicationContext中,getEnvironment返回的是ConfigurableEnvironment,也意味着用户可以修改Environment对象。

ApplicationContext是beanfactory的一个扩展容器,继承了ListableBeanFactory,ResourceLoader,ApplicationEventPublisher接口,因此ApplicationContext除了支持beanfactory的功能,还支持加载资源,发布事件,支持国际化等,当然ApplicationContext运行的过程中仅支持可读,不能够进行更改,不过注意的是实现类可以重新加载容器。                                ConfigurableApplicationContext继承了ApplicationContext,能够更加灵活的配置容器,比如重新配置环境,增加beanfactory后置处理,追加事件监听器,另外大名鼎鼎的refresh方法就是此接口定义的。

AbstractApplicationContext是ConfigurableApplicationContext的抽象实现类,使用了模板方法设计模式,由子类具体实现,AbstractApplicationContext能够自动注册一些定义在容器内部的bean,包括BeanFactoryPostProcessors、BeanPostProcessors、ApplicationListener,这个等会在源码跟踪的时候在详细阐述。GenericApplicationContext继承了ConfigurableApplicationContext,它有个DefaultListableBeanFactory成员对象,DefaultListableBeanFactory是个很牛逼的beanfactory实现类,可以拿着DefaultListableBeanFactory对象对beanfactory进行很多操作,另外它实现了BeanDefinitionRegistry接口,表示能够将BeanDefinition注册到容器中,下面给出GenericApplicationContext容器的使用代码案例。

 GenericApplicationContext ctx = new GenericApplicationContext();XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties"));ctx.refresh();
AnnotationConfigApplicationContext继承了GenericApplicationContext,支持注解式注入,可以使用Configuration,
Component,Bean注解啥的。 

二、知识准备

首先要明确一点,在普通的java程序中,是由一个一个对象构成,生命周期是new出来之后,然后由jvm进行销毁,而在spring中,是由bean构成,spring容器管理的是bean,其中最重要的就是一个叫BeanDefinition的数据结构,它是对bean的描述,在BeanDefinition中定义各种bean的属性,比如这个bean是否是单例,是否懒加载,它的类对象是啥等等,所以spring在容器启动过程中,会先将一个一个类转化成BeanDefinition,并存放到一个beanDefinitionMap的map集合,key为beanDefinition的名字,value为beanDefinition,然后根据这个map集合的BeanDefinition所描述的信息,生成实例对象。然后梳理下我们需要知道的AnnotationConfigApplicationContext的数据结构,AnnotationConfigApplicationContext下有个beanfactory的成员变量,它会在调用AnnotationConfigApplicationContext的构造方法中被创建,类型为defaultListableBeanFactory,beanfactory下有个beanDefinitionMap的成员变量,beanDefinitionMap是一个map集合,key为beanDefinition的名字,value为beanDefinition。

三、启动过程分析

看下最基本的启动 AnnotationConfigApplicationContext 容器的例子:

@Configuration
@ComponentScan("com.ls")
public class App
{public static void main( String[] args ){AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(App.class);context.getBean("student");}
}@Component
public class Student {private  String name;
}

接下来点进去,发现调用了三个方法,this()、register(componentClasses)、refresh()。

   public AnnotationConfigApplicationContext(Class<?>... componentClasses) {/**1.生成了一个DefaultListableBeanFactory的beanfactory2.生成一个reader和scanner对象,用于beandifinition的注册3.将一些beanfactoryProcessor注册到beanfactory中,其中有个            ConfigurationClassPostProcessor的beanfactoryProcessor这个很关键,后面它用来解析                component注解,componentscan注解,import注解等等。*/this();/**将启动的类注册到容器中*/register(componentClasses);/**调用刷新方法,这个方法很关键,spring最核心的方法,接下来着重分析这个方法*/refresh();}

点击refresh方法,进入方法体,发现里面代码其实也不多,但里面很复杂,我先大概讲解下每个方法的作用,大家可以先留个印象。我这里说的把类注册到容器的意思是指这个类的beandifinition put到beandifinitionMap中。

@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 容器刷新工作进行的准备//设置定时器,容器的状态设置为激活prepareRefresh();// 获取那个beanFactory对象,其实就是上步那个this()方法中创建的                //DefaultListableBeanFactory对象,这个代码很简单,下面就不点进去看了。ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 配置beanfactory,比如说classloader,post-processorsprepareBeanFactory(beanFactory);try {// 这个是扩展方法,由子类进行重写,对beanfactory进行操作。postProcessBeanFactory(beanFactory);// 调用那些已经注册在beanfactory中的beanfactoryPostProcessors,前面提到过//this方法中,已经注册过一些beanfactoryPostProcessors,就会在这里调用,//ConfigurationClassPostProcessor这个调用完成后是会把component注解,    //componentscan注解的规则的类注册到beanfactory,也就是说会将student这个//类注册到beanfactory中,也就是beandifinitionMap中了。invokeBeanFactoryPostProcessors(beanFactory);//BeanPostProcessors注册到beanfactory中。registerBeanPostProcessors(beanFactory);// 这个是用于国际化的,暂时先忽略。initMessageSource();//初始化事件多播器,用于发布事件initApplicationEventMulticaster();// 由子类重写,在springboot中就重写这个方法,用于启动嵌入式web容器onRefresh();// 注册事件监听器。registerListeners();// 初始化所有单例的实例finishBeanFactoryInitialization(beanFactory);//结果刷新,发布有关事件,前面注册的监听器可以进行监听,这个方法很复杂,后面的博客在进行讲解。finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}}

prepareRefresh方法是容器刷新前的准备工作,比如定时器,激活标识以及初始化一些源文件的环境属性。

 protected void prepareRefresh() {// 开始计时this.startupDate = System.currentTimeMillis();//设置状态this.closed.set(false);this.active.set(true);//打印debug日志if (logger.isDebugEnabled()) {if (logger.isTraceEnabled()) {logger.trace("Refreshing " + this);}else {logger.debug("Refreshing " + getDisplayName());}}// 初始化配置的环境属性,由子类重写initPropertySources();// 验证属性getEnvironment().validateRequiredProperties();}

invokeBeanFactoryPostProcessors方法主要是调用beanfactoryPostProcessors方法,也是一个重点方法,

   protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());}

继续点进PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());会发现这个方法超长,先不慌,其实逻辑很简单。

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {Set<String> processedBeans = new HashSet<>();//可以看上面继承图,这个条件是满足的if (beanFactory instanceof BeanDefinitionRegistry) {/**BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口,BeanDefinitionRegistryPostProcessor主要是向beanfactory注册beandifinition 的。这里regularPostProcessors存储BeanFactoryPostProcessor的实现类,registryProcessors存储BeanDefinitionRegistryPostProcessor的实现类。*/BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {BeanDefinitionRegistryPostProcessor registryProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;registryProcessor.postProcessBeanDefinitionRegistry(registry);registryProcessors.add(registryProcessor);}else {regularPostProcessors.add(postProcessor);}}//调用步骤为分别顺序调用实现了 PriorityOrdered, Ordered, 其他接口的    //BeanDefinitionRegistryPostProcessorsList<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();//第一步先调用实现了PriorityOrdered的BeanDefinitionRegistryPostProcessorsString[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// 然后调用实现了Ordered的BeanDefinitionRegistryPostProcessorspostProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// 最后调用剩余的BeanDefinitionRegistryPostProcessorsboolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();}//然后调用 postProcessBeanFactory中的方法invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}else {invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// 隔离开来实现了 PriorityOrdered, 或者Ordered,或者其他的beanFactoryPostProcessorList<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();for (String ppName : postProcessorNames) {if (processedBeans.contains(ppName)) {}else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}}//第一步调用实现PriorityOrdered的beanFactoryPostProcessorsortPostProcessors(priorityOrderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// 然后调用实现Ordered的beanFactoryPostProcessorList<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(orderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// 最后调用其他的List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();for (String postProcessorName : nonOrderedPostProcessorNames) {nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);beanFactory.clearMetadataCache();}

上面有个重要的BeanDefinitionRegistryPostProcessor值得说下,就是前面一直强调的ConfigurationClassPostProcessor,看看它的postProcessBeanDefinitionRegistry方法,里面有个parser.parse(candidates)方法,这个方法解析了@configuration,@componentscan,@import等等注解,继续点进那个parser.parse(candidates)方法,看到有个parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName())的方法,再继续进入processConfigurationClass方法,在继续进入doProcessConfigurationClass方法,终于找到解析注解的地方了。

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)throws IOException {if (configClass.getMetadata().isAnnotated(Component.class.getName())) {// Recursively process any member (nested) classes firstprocessMemberClasses(configClass, sourceClass);}//处理 @PropertySource 注解for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class,org.springframework.context.annotation.PropertySource.class)) {if (this.environment instanceof ConfigurableEnvironment) {processPropertySource(propertySource);}else {logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +"]. Reason: Environment must implement ConfigurableEnvironment");}}//处理 @ComponentScan 注解Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {for (AnnotationAttributes componentScan : componentScans) {// The config class is annotated with @ComponentScan -> perform the scan immediatelySet<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if neededfor (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}}}// 解析 @Import 注解processImports(configClass, sourceClass, getImports(sourceClass), true);// 解析 @ImportResource 注解AnnotationAttributes importResource =AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);if (importResource != null) {String[] resources = importResource.getStringArray("locations");Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");for (String resource : resources) {String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);configClass.addImportedResource(resolvedResource, readerClass);}}// 解析 @Bean 注解Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}processInterfaces(configClass, sourceClass);// 解析父类if (sourceClass.getMetadata().hasSuperClass()) {String superclass = sourceClass.getMetadata().getSuperClassName();if (superclass != null && !superclass.startsWith("java") &&!this.knownSuperclasses.containsKey(superclass)) {this.knownSuperclasses.put(superclass, configClass);// Superclass found, return its annotation metadata and recursereturn sourceClass.getSuperClass();}}// 整个解析过程完成return null;}

四、结语

这篇先暂时将spring源码介绍到这,下篇将详细介绍finishBeanFactoryInitialization实例化所有单例对象方法,从源码角度分析spring bean的生命周期和spring是如何解决循环依赖等等。

庖丁解牛之spring源码系列一相关推荐

  1. Spring源码系列:依赖注入(二)createBean

    在Spring源码系列:依赖注入(一)(AbstractBeanFactory-getBean)最后说道getBean是依赖注入的起点,bean的创建都是通过createBean来完成具体的创建的.c ...

  2. Spring源码系列:BeanDefinition载入(下)

    在Spring源码系列:BeanDefinition载入(上)中已经大概捋了一下解析过程,本篇将记录一下bean的注册过程. bean的注册就是DefaultListableBeanFactory中r ...

  3. Ioc容器beanDefinition-Spring 源码系列(1)

    Ioc容器beanDefinition-Spring 源码系列(1) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器 ...

  4. Spring源码系列(十二)Spring创建Bean的过程(二)

    1.写在前面 上篇博客主要Spring在创建Bean的时候,第一次调用的Bean的后置处理器的过程,同时笔者也打算将整个Spring创建的Bean的过程,通过这个系列,将Bean的创建过程给讲清楚,废 ...

  5. Spring源码系列- Spring Beans - 核心类的基本介绍

    Spring源码系列- Spring Beans - 核心类的基本介绍 读过上一篇文章的读者应该都能对Spring的体系结构有一个大致的了解,在结尾处,我也说过会从spring-beans包开始分析, ...

  6. 【spring源码系列-05】refresh中prepareRefresh方法的执行流程

    Spring源码系列整体栏目 内容 链接地址 [一]spring源码整体概述 https://blog.csdn.net/zhenghuishengq/article/details/13094088 ...

  7. Spring源码系列:BeanFactory的创建

    2019独角兽企业重金招聘Python工程师标准>>> Spring的Ioc容器其实就是一个bean的关系网,依赖于core,bean,context三个组件来构建的.在spring ...

  8. Spring源码系列(十三)——Spring源码编译及详细注解

    文章目录 1. 环境搭建 2. 代码编译 2.1 编译代码 2.1.1 build.gradle 2.1.1.1 第一处 2.1.1.2 第二处 2.1.2 gradle.properties 2.1 ...

  9. spring源码系列一--BeanDefinition

    如果说java是由对象组成,那么spring-framework框架可以说是由BeanDefinition所构成.BeanDefinitiion其实是spring中的顶级接口,我们在阅读源码之前必须要 ...

  10. Spring源码系列-第1章-Spring源码纵览【持续更新中】

    文章目录 必读 第1章-Spring源码纵览 概述 简单的继承关系图 Spring框架整体流程 核心组件接口分析 Resource资源 方法 实现类 ResourceLoader资源加载器 方法 实现 ...

最新文章

  1. 洛谷P1462 通往奥格瑞玛的道路 二分答案+最短路SPFA
  2. gulp es5语法转换及js/css/html压缩过程
  3. 17校招真题题集(2)6-10
  4. django2自动发现项目中的url
  5. 玩个锤子,李飞飞夫妇团队的最新研究
  6. Linux平台下卸载ORACLE
  7. MacBook Touch Bar(触控栏)无法正常工作的解决方法
  8. win10下如何装win7
  9. 联想拯救者Y7000重装win10系统卡在logo界面
  10. 无刷电机控制基础(1)——结构和驱动电路
  11. OpenStack Kolla-Ansible部署Trove数据库服务Daas,部署Ceilometer数据收集服务,Gnocchi对接Ceph
  12. qmail 相关问题
  13. Javascript_ES5_学习笔记
  14. Python——函数的嵌套
  15. php ceil(向上)、floor(向下取整)、 intval(取整数值) 、floatval(取浮点值)
  16. 如何使用Bancor避免无常损失
  17. java计算机毕业设计邻里平台源码+系统+mysql数据库+lw文档
  18. mysql怎么用_如何使用MySQL数据库
  19. 基于理赔流程的车险反欺诈研究
  20. SCRIPT5007: 无法获取未定义或 null 引用的属性“call”

热门文章

  1. Myeclipse10如何进行代码提示和自动补全
  2. mysql经典46_mysql练习46题 PDF 下载
  3. 系统运维方案_传统运维 VS 互联网运维 框架体系大观
  4. 高通笔记本装linux,在华硕畅370(TP370QL)骁龙笔记本上安装Ubuntu 18.04 ARM64的方法...
  5. Code::Blocks代码自动提示设置及常用快捷键 .
  6. AutoViz:用一行代码自动可视化任何大小的任何数据集
  7. 蓝桥杯 java 组素数_第四届蓝桥杯javaC组_组素数
  8. html和body高度不一致,即使html和body都是容器流体的高度不是100%
  9. 怎么判断间隙过渡过盈配合_什么是间隙配合、过盈配合、过渡配合?它们在汽车上有哪些应用?...
  10. 算法:两个数的和等于指定值1. Two Sum