Spring源码剖析1:初探Spring IOC核心流程
本文大致地介绍了ioc容器的初始化过程,只列出了比较重要的过程和代码,可以从中看出ioc容器执行的大致流程。
接下来的文章会更加深入剖析bean容器如何解析xml,注册和初始化bean,以及如何获取bean实例等详细的过程。
转自:
1. 初始化
大致单步跟了下spring ioc的初始化过程,整个脉络很庞大,初始化的过程主要就是读取xml资源,并解析,最终注册到bean factory中:
在完成初始化的过程后,bean们就在beanfactory中蓄势以待地等调用了。下面通过一个具体的例子,来详细地学习一下初始化过程,例如当加载下面一个bean:
<bean id="xiaowang" class="com.springstudy.talentshow.superinstrumentalist"> <property name="instruments"> <list> <ref bean="piano"/> <ref bean="saxophone"/> </list> </property> </bean>
加载时需要读取、解析、注册bean,这个过程具体的调用栈如下所示:
下面对每一步的关键的代码进行详细分析:
准备
保存配置位置,并刷新
在调用classpathxmlapplicationcontext后,先会将配置位置信息保存到configlocations,供后面解析使用,之后,会调用abstractapplicationcontext
的refresh方法进行刷新:
public classpathxmlapplicationcontext(string[] configlocations, boolean refresh, applicationcontext parent) throws beansexception { super(parent); // 保存位置信息,比如`com/springstudy/talentshow/talent-show.xml` setconfiglocations(configlocations); if (refresh) { // 刷新 refresh(); } } public void refresh() throws beansexception, illegalstateexception { synchronized (this.startupshutdownmonitor) { // prepare this context for refreshing. preparerefresh(); // tell the subclass to refresh the internal bean factory. configurablelistablebeanfactory beanfactory = obtainfreshbeanfactory(); // prepare the bean factory for use in this context. preparebeanfactory(beanfactory); try { // allows post-processing of the bean factory in context subclasses. postprocessbeanfactory(beanfactory); // invoke factory processors registered as beans in the context. invokebeanfactorypostprocessors(beanfactory); // register bean processors that intercept bean creation. registerbeanpostprocessors(beanfactory); // initialize message source for this context. initmessagesource(); // initialize event multicaster for this context. initapplicationeventmulticaster(); // initialize other special beans in specific context subclasses. onrefresh(); // check for listener beans and register them. registerlisteners(); // instantiate all remaining (non-lazy-init) singletons. finishbeanfactoryinitialization(beanfactory); // last step: publish corresponding event. finishrefresh(); } catch (beansexception ex) { // destroy already created singletons to avoid dangling resources. destroybeans(); // reset 'active' flag. cancelrefresh(ex); // propagate exception to caller. throw ex; } } }
创建载入beanfactory
protected final void refreshbeanfactory() throws beansexception { // ... ... defaultlistablebeanfactory beanfactory = createbeanfactory(); // ... ... loadbeandefinitions(beanfactory); // ... ... }
创建xmlbeandefinitionreader
protected void loadbeandefinitions(defaultlistablebeanfactory beanfactory) throws beansexception, ioexception { // create a new xmlbeandefinitionreader for the given beanfactory. xmlbeandefinitionreader beandefinitionreader = new xmlbeandefinitionreader(beanfactory); // ... ... // allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initbeandefinitionreader(beandefinitionreader); loadbeandefinitions(beandefinitionreader);
读取
创建处理每一个resource
public int loadbeandefinitions(string location, set<resource> actualresources) throws beandefinitionstoreexception { // ... ... // 通过location来读取resource resource[] resources = ((resourcepatternresolver) resourceloader).getresources(location); int loadcount = loadbeandefinitions(resources); // ... ... } public int loadbeandefinitions(resource... resources) throws beandefinitionstoreexception { assert.notnull(resources, "resource array must not be null"); int counter = 0; for (resource resource : resources) { // 载入每一个resource counter += loadbeandefinitions(resource); } return counter; }
处理xml每个元素
protected void parsebeandefinitions(element root, beandefinitionparserdelegate delegate) { // ... ... nodelist nl = root.getchildnodes(); for (int i = 0; i < nl.getlength(); i++) { node node = nl.item(i); if (node instanceof element) { element ele = (element) node; if (delegate.isdefaultnamespace(ele)) { // 处理每个xml中的元素,可能是import、alias、bean parsedefaultelement(ele, delegate); } else { delegate.parsecustomelement(ele); } } } // ... ... }
解析和注册bean
protected void processbeandefinition(element ele, beandefinitionparserdelegate delegate) { // 解析 beandefinitionholder bdholder = delegate.parsebeandefinitionelement(ele); if (bdholder != null) { bdholder = delegate.decoratebeandefinitionifrequired(ele, bdholder); try { // 注册 // register the final decorated instance. beandefinitionreaderutils.registerbeandefinition( bdholder, getreadercontext().getregistry()); } catch (beandefinitionstoreexception ex) { getreadercontext().error("failed to register bean definition with name '" + bdholder.getbeanname() + "'", ele, ex); } // send registration event. getreadercontext().firecomponentregistered(new beancomponentdefinition(bdholder)); } }
本步骤中,通过parsebeandefinitionelement将xml的元素解析为beandefinition,然后存在beandefinitionholder中,然后再利用beandefinitionholder将beandefinition注册,实质就是把beandefinition的实例put进beanfactory中,和后面将详细的介绍解析和注册过程。
解析
处理每个bean的元素
public abstractbeandefinition parsebeandefinitionelement( element ele, string beanname, beandefinition containingbean) { // ... ... // 创建beandefinition abstractbeandefinition bd = createbeandefinition(classname, parent); parsebeandefinitionattributes(ele, beanname, containingbean, bd); bd.setdescription(domutils.getchildelementvaluebytagname(ele, description_element)); parsemetaelements(ele, bd); parselookupoverridesubelements(ele, bd.getmethodoverrides()); parsereplacedmethodsubelements(ele, bd.getmethodoverrides()); // 处理“constructor” parseconstructorargelements(ele, bd); // 处理“preperty” parsepropertyelements(ele, bd); parsequalifierelements(ele, bd); // ... ... }
处理属性的值
public object parsepropertyvalue(element ele, beandefinition bd, string propertyname) { string elementname = (propertyname != null) ? "<property> element for property '" + propertyname + "'" : "<constructor-arg> element"; // ... ... if (hasrefattribute) { // 处理引用 string refname = ele.getattribute(ref_attribute); if (!stringutils.hastext(refname)) { error(elementname + " contains empty 'ref' attribute", ele); } runtimebeanreference ref = new runtimebeanreference(refname); ref.setsource(extractsource(ele)); return ref; } else if (hasvalueattribute) { // 处理值 typedstringvalue valueholder = new typedstringvalue(ele.getattribute(value_attribute)); valueholder.setsource(extractsource(ele)); return valueholder; } else if (subelement != null) { // 处理子类型(比如list、map等) return parsepropertysubelement(subelement, bd); } // ... ... }
1.4 注册
public static void registerbeandefinition( beandefinitionholder definitionholder, beandefinitionregistry registry) throws beandefinitionstoreexception { // register bean definition under primary name. string beanname = definitionholder.getbeanname(); registry.registerbeandefinition(beanname, definitionholder.getbeandefinition()); // register aliases for bean name, if any. string[] aliases = definitionholder.getaliases(); if (aliases != null) { for (string alias : aliases) { registry.registeralias(beanname, alias); } } } public void registerbeandefinition(string beanname, beandefinition beandefinition) throws beandefinitionstoreexception { // ...... // 将beandefinition注册 this.beandefinitionmap.put(beanname, beandefinition); // ...... }
注册过程中,最核心的一句就是:this.beandefinitionmap.put(beanname, beandefinition),也就是说注册的实质就是以beanname为key,以beandefinition为value,将其put到hashmap中。
注册
public static void registerbeandefinition( beandefinitionholder definitionholder, beandefinitionregistry registry) throws beandefinitionstoreexception { // register bean definition under primary name. string beanname = definitionholder.getbeanname(); registry.registerbeandefinition(beanname, definitionholder.getbeandefinition()); // register aliases for bean name, if any. string[] aliases = definitionholder.getaliases(); if (aliases != null) { for (string alias : aliases) { registry.registeralias(beanname, alias); } } } public void registerbeandefinition(string beanname, beandefinition beandefinition) throws beandefinitionstoreexception { // ...... // 将beandefinition注册 this.beandefinitionmap.put(beanname, beandefinition); // ......
理解了以上两个过程,我们就可以自己实现一个简单的spring框架了。于是,我根据自己的理解实现了一个简单的ioc框架simple spring,有兴趣可以看看。
注册过程中,最核心的一句就是:this.beandefinitionmap.put(beanname, beandefinition)
,也就是说注册的实质就是以beanname为key,以beandefinition为value,将其put到hashmap中。
注入依赖
当完成初始化ioc容器后,如果bean没有设置lazy-init(延迟加载)属性,那么bean的实例就会在初始化ioc完成之后,及时地进行初始化。初始化时会先建立实例,然后根据配置利用反射对实例进行进一步操作,具体流程如下所示:
创建bean的实例
创建bean的实例过程函数调用栈如下所示:
注入bean的属性
注入bean的属性过程函数调用栈如下所示:
在创建bean和注入bean的属性时,都是在docreatebean函数中进行的,我们重点看下:
protected object docreatebean(final string beanname, final rootbeandefinition mbd, final object[] args) { // instantiate the bean. beanwrapper instancewrapper = null; if (mbd.issingleton()) { instancewrapper = this.factorybeaninstancecache.remove(beanname); } if (instancewrapper == null) { // 创建bean的实例 instancewrapper = createbeaninstance(beanname, mbd, args); } // ... ... // initialize the bean instance. object exposedobject = bean; try { // 初始化bean的实例,如注入属性 populatebean(beanname, mbd, instancewrapper); if (exposedobject != null) { exposedobject = initializebean(beanname, exposedobject, mbd); } } // ... ... }
理解了以上两个过程,我们就可以自己实现一个简单的spring框架了。于是,我根据自己的理解实现了一个简单的ioc框架simple spring,有兴趣可以看看。
推荐阅读
-
Spring源码剖析1:初探Spring IOC核心流程
-
荐 Java 源码剖析(12)--浅谈 Spring IoC 和 DI
-
Spring IoC源码分析-02深入源码流程分析
-
Spring IOC 容器预启动流程源码探析
-
Spring源码剖析2:Spring IOC容器的加载过程
-
Spring源码--IOC容器实现(1)--IOC容器结构体系
-
Spring源码剖析1:初探Spring IOC核心流程
-
源码剖析springAOP的执行流程(注解方式启动spring)
-
荐 Java 源码剖析(12)--浅谈 Spring IoC 和 DI
-
Spring基本用法1——Spring的核心机制:IOC、DI