SpringIOC容器(一)

三.IOC启动流程分析法

我们从ClasspathXmlApplicationContext的构造方法说起

3,1:调用父类的构造方法,进行相关的对象创建工作,跟踪到父类AbstractApplicationContext,看到首先创建了一个资源式解析器PathMatchingResourcePatternResover,它是用来解析XML的,后面会用到。

3.2:setConfigLocations,设置配置文件的路径,也就是将classpath:spring-config.xml设置到configLocations成员变量中,后面读取XML配置文件时会用到。setConfigLocations内部还调用了resolvePath()方法,主要完成了Enviroment环境对象的创建,以及配置文件中的${xxx}占位符的替换操作。当执行resolvePath()方法里的new StandardEnviroment()构造方法时,首先会调用父类的AbbstractEnviroment的构造方法,留意到customizePropertySource()方法是空实现的,那么就看子类StandardEnviroment是否有重写customizePropertySource()方法。果然StandardEnviroment重写了额customizePropertySource()方法,里面执行了一个很关键的逻辑:通过System.getProperties()读取我们系统的属性,通过Ssytem.getenv()获取系统变量,并把他们添加到系统属性里面,后面就可以直接拿出来。getEnviroment()方法执行完后,接着调用resolveRequiredPlaceholders(path),这个方法的作用是解析文本中的${xxx}占位符,例如${db.username},${db.driverClass}等占位符,spring就会将他们解析成具体的值。

3.3:调用refresh()方法,这是整个IOC容器的核心。里面总共有12个方法,之后会详细分析。为什么要是refresh()方法,而不是init()呢,因为refresh()会把之前的的ApplicationContext销毁,然后再重新执行一次初始化操作。

接下来12个方法重点逐一分析:

四.prepareRefresh():创建bean容器前的准备工作。

主要完成容器刷新前的一些准备工作,如设置启动时间,一些标志位等。另外,我们也可以通过重写initPropertySource()方法实现校验一些属性的必填

五.obtainFreshBeanFactory():创建bean容器

该方法是IOC容器中一个重要的方法,主要创建了一个IOC容器DefaultListableBeanFactroy,通过读取XML配置文件,并解析封装成一个个BeanDefinition(bean定义信息),然后注册到Bean工厂中。主要关注refreshBeanFactory()方法。

5.1:obtainFreshBeanFactory()第一步:销毁之前已经存在的bean工厂以及对应的bean。

5.2:obtainFreshBeanFactory()第二步:创建DefaultListableBeanFactory bean工厂。通过createBeanFactory()方法创建。留意一下BeanFactory两个重要的属性,BeanDefinition定义信息和beanName集合。

private final Map<String,BeanDefinition>  beanDefinition=new ConcurrentHashMap<>(256);

private volatile List<String> beanDefinitionNames=new ArrayList<>(256);

5.3:obtainFreshBeanFactory()第三步:定制化bean工厂

通过customizeBeanFactory()方法定制化bean工厂,也就是设置两个属性值而已:

是否允许覆盖同名称的不同定义的对象;

四否允许循环依赖;

对于这个属性值,不为空的时候才进行设置。

同样我们可以自定义ClassPathXmlApplicationContext来定制话设置这两个属性值。

5.4:obtainFreshBeanFactory()第四步:读取,解析配置文件,加载bean定义一级注册bean。o

refreshBeanFactororyy最后一步,也是最重要的一个环节,调用loadBeanDefinitions(beanFact)方法,主要完成XML配置文件的读取,解析以及向bean工厂注册bean的工作.

首先为给定的BeanFactory创建一个配置文件读取器XmlBeanDefinitionReader,接着设置一些beanDefinitonReader属性,如环境对象,资源加载器等,最后通过BeanDeginitionReader加载bean定义信息。其中因为配置文件可能存在多个,所以需要循环进行读取。而后,通过ResourcePatternResolver将配文件的路径转化为具体的Resource后,又调用loadBeanDefinitions(resources)重载方法,通过resource来加载bean定义信息。上述主要的工作其实就是从encodedResoure中获取已经封装好的Resource对象,再根据Resource对象获取对应的输入流,前面一系列都是准备工作,接下来是重点读取过程方法doLoadBeanDefinitions(inputSource,encodeResource.getResource()。

doLoadBeanDefinitions()方法主要完成了两件事请:

1.doLoadDocument(inputSoure,resource):将XML配置文件转化为Document文档对象,由documentLoader完成,spring使用SAX的方式去解 析XML文件,封装成Document文档对 象;

2.registerBeanDefinitons(doc,resource):从document文档解析,注册bean定义信息。

接着主要看看registerBeanDefinitons方法:

首先创建了一个创建文档读取器对象,然后通过读取器加载及注册bean。继续追踪,可以看到doRegisterBeanDefinitions(Element root)方法,主要逻辑在最后三个方法:

1.preProcessXml():留给子类扩展,可以进行解析XML前置一些工作

2.parseBeanDefinitons():解析bean定义,具体解析各个标签的方法

3.postProcessXml():留给子类扩展,可以进行解析XML后置的一些处理

下面来分析parseBeanDefinitions()方法:要解析分为两种:

1.默认命名空间解析:对默认命名空间的解析过程,主要针对<import/>,<alias/>,<bean/>,<beans/>标签进行解析

2.自定义命名空间解析:自定义标签的解析过程

对bean标签的解析非常重要,理解了bean标签的解析过程就理解了其他标签的解析过程,主要看一下processBeanDefinitions()方法:委托BeanDefinitionParseDelegate进行元素的解析,返回BeanDefinitionHolder实例的bdHolder,经过这个方法后,bdHolder实例已经包含我们配置文件中各种属性了,如class,id,name等属性。继续看parseBeanDefiitionElement()方法。可以看到Spring解析bean标签中一系列常用的属性。

第一步:创建用于属性承载的BeanDefinition;

第二步:解析bean标签的其他一些属性,如autowired,singleton,layy-init,scop,primary

第三步:解析meta标签,构造方法参数,property子元素等信息、

到这里,配置文件的解析已经完成,剩下的就是把它注册到工厂中。Spring通过BeanDefinitionReaderUtils.registerBeanDefinition()来实现bean定义信息的注册。解析的XML,会将对应的信息封装成BeanDefinition对象,然后注册到BeanDefinitionRegistry类型的实例registry中。对于注册BeanDefinition,分为了两个部分:

1.beanName的注册

2.通过别名的注册

最后,就将这个bean定义信息注册到了工厂中

六.prepareBeanFactory(beanFactory):准备bean工厂,设置类加载器,添加一些BeanPostProcessor等

七.postProcessBeanFactory(beanFactory):留给子类对BeanFactory定制化处理。

Spring中没有具体去实现postProecssBeanFacory()方法,他是一个模版方法,留给子类去拓展,作用是在BeanFactory准备工作完成后做一些定制化的处理,一般结合BeanPostProcess接口的实现类一起使用,如注入一些重要资源等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值