ioc容器源码分析(一)

<div id="article_content" class="article_content tracking-ad" data-mod="popu_307" data-dsm="post">

<p>我们前面一直以BeanFactory接口以及它的默认实现类XmlBeanFactory为例进行分析,但是<a href="http://lib.csdn.net/base/javaee" class="replace_word" title="Java EE知识库" target="_blank" style="color:#df3434; font-weight:bold;">spring</a>中还提供了另一个接口ApplicationContext,用于扩展BeanFactory中现有的功能。</p>
<p>ApplicationContext和BeanFactory两者都是用于加载Bean的,但是相比之下,ApplicationContext提供了更多的扩展功能,简而言之:ApplicationContext包含BeanFactory的所有功能。通常建议比BeanFactory优先,除非在一些限制的场合,比如字节长度对内存有很大的影响时(Applet).绝大多数“典型的”企业应用系统,ApplicationContext就是需要使用的。</p>
<p>那么究竟ApplicationContext比BeanFactory多了哪些功能?首先我们来看看使用两个不同的类去加载配置文件在写法上的不同。</p>
<ul>
<li>使用BeanFactory方式加载XML.</li></ul>
<p><br>
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));</p>
<ul>
<li>使用ApplicationContext方式加载XML.</li></ul>
<p>ApplicationContext bf = new ClassPathXmlApplicationContext("beanFactoryTest.xml");</p>
<p>我们以ClassPathXmlApplicationContext作为切入点,开始对整体功能进行分析。</p>
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" target="_blank">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" target="_blank">copy</a><div style="position: absolute; left: 762px; top: 939px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_1" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=1&width=18&height=18" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" target="_blank">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;" target="_blank">?</a></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">public</span><span> ClassPathXmlApplicationContext(String configLocation) </span><span class="keyword">throws</span><span> BeansException {  </span></span></li><li class=""><span>    <span class="keyword">this</span><span>(</span><span class="keyword">new</span><span> String[] {configLocation}, </span><span class="keyword">true</span><span>, </span><span class="keyword">null</span><span>);  </span></span></li><li class="alt"><span>}  </span></li></ol></div><pre code_snippet_id="1761056" snippet_file_name="blog_20160713_1_6743937" name="code" class="java" style="display: none;">	public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
	}</pre><br>
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" target="_blank">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" target="_blank">copy</a><div style="position: absolute; left: 762px; top: 1097px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_2" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_2" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=2&width=18&height=18" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" target="_blank">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;" target="_blank">?</a></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">public</span><span> ClassPathXmlApplicationContext(String[] configLocations, </span><span class="keyword">boolean</span><span> refresh, ApplicationContext parent)  </span></span></li><li class=""><span>        <span class="keyword">throws</span><span> BeansException {  </span></span></li><li class="alt"><span>  </span></li><li class=""><span>    <span class="keyword">super</span><span>(parent);  </span></span></li><li class="alt"><span>    setConfigLocations(configLocations);  </span></li><li class=""><span>    <span class="keyword">if</span><span> (refresh) {  </span></span></li><li class="alt"><span>        refresh();  </span></li><li class=""><span>    }  </span></li><li class="alt"><span>}  </span></li></ol></div><pre code_snippet_id="1761056" snippet_file_name="blog_20160713_2_1139566" name="code" class="java" style="display: none;">	public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {

		super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
	}</pre><br>
设置路径是必不可少的步骤<span style="font-size:12px">,ClassPathXmlApplicationContext中可以将配置文件路径以数组的方式传入,ClassPathXmlApplicationContext可以对数组进行解析并进行加载。而对于解析及功能实现都在refresh()中实现。</span>
<p></p>
<p><span style="font-size:18px"><strong>1.设置配置路径</strong></span></p>
<p><span style="font-size:12px">在ClassPathXmlApplicationContext中支持多个配置文件以数组方式同时传入:</span></p>
<p><span style="font-size:12px"></span></p>
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" target="_blank">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" target="_blank">copy</a><div style="position: absolute; left: 762px; top: 1504px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_3" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_3" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=3&width=18&height=18" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" target="_blank">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;" target="_blank">?</a></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> setConfigLocations(String[] locations) {  </span></span></li><li class=""><span>        <span class="keyword">if</span><span> (locations != </span><span class="keyword">null</span><span>) {  </span></span></li><li class="alt"><span>            Assert.noNullElements(locations, <span class="string">"Config locations must not be null"</span><span>);  </span></span></li><li class=""><span>            <span class="keyword">this</span><span>.configLocations = </span><span class="keyword">new</span><span> String[locations.length];  </span></span></li><li class="alt"><span>            <span class="keyword">for</span><span> (</span><span class="keyword">int</span><span> i = </span><span class="number">0</span><span>; i < locations.length; i++) {  </span></span></li><li class=""><span>                <span class="keyword">this</span><span>.configLocations[i] = resolvePath(locations[i]).trim();  </span></span></li><li class="alt"><span>            }  </span></li><li class=""><span>        }  </span></li><li class="alt"><span>        <span class="keyword">else</span><span> {  </span></span></li><li class=""><span>            <span class="keyword">this</span><span>.configLocations = </span><span class="keyword">null</span><span>;  </span></span></li><li class="alt"><span>        }  </span></li><li class=""><span>    }  </span></li></ol></div><pre code_snippet_id="1761056" snippet_file_name="blog_20160713_3_6995890" name="code" class="java" style="display: none;">public void setConfigLocations(String[] locations) {
		if (locations != null) {
			Assert.noNullElements(locations, "Config locations must not be null");
			this.configLocations = new String[locations.length];
			for (int i = 0; i < locations.length; i++) {
				this.configLocations[i] = resolvePath(locations[i]).trim();
			}
		}
		else {
			this.configLocations = null;
		}
	}</pre><br>
<span style="font-size:18px"><strong>2.扩展功能</strong></span>
<p></p>
<p>设置了路径之后,便可以根据路径做配置文件的解析以及各种功能的实现了。可以说refresh函数中包含了几乎ApplicationContext中提供的全部功能,而且此函数中逻辑非常清晰明了,使我们很容易分析对应的层次及逻辑</p>
<p></p>
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" target="_blank">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" target="_blank">copy</a><div style="position: absolute; left: 762px; top: 1929px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_4" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_4" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=4&width=18&height=18" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" target="_blank">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;" target="_blank">?</a></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> refresh() </span><span class="keyword">throws</span><span> BeansException, IllegalStateException {  </span></span></li><li class=""><span>    <span class="keyword">synchronized</span><span> (</span><span class="keyword">this</span><span>.startupShutdownMonitor) {  </span></span></li><li class="alt"><span>        <span class="comment">// Prepare this context for refreshing.</span><span>  </span></span></li><li class=""><span>        <span class="comment">//准备刷新的上下文 环境</span><span>  </span></span></li><li class="alt"><span>        <span class="comment">/*</span> </span></li><li class=""><span><span class="comment">         * 初始化前的准备工作,例如对系统属性或者环境变量进行准备及验证。</span> </span></li><li class="alt"><span><span class="comment">         * 在某种情况下项目的使用需要读取某些系统变量,而这个变量的设置很可能会影响着系统</span> </span></li><li class=""><span><span class="comment">         * 的正确性,那么ClassPathXmlApplicationContext为我们提供的这个准备函数就显得非常必要,</span> </span></li><li class="alt"><span><span class="comment">         * 它可以在Spring启动的时候提前对必须的变量进行存在性验证。</span> </span></li><li class=""><span><span class="comment">         */</span><span>  </span></span></li><li class="alt"><span>        prepareRefresh();  </span></li><li class=""><span>  </span></li><li class="alt"><span>        <span class="comment">// Tell the subclass to refresh the internal bean factory.</span><span>  </span></span></li><li class=""><span>        <span class="comment">//初始化BeanFactory,并进行XML文件读取</span><span>  </span></span></li><li class="alt"><span>        <span class="comment">/*</span> </span></li><li class=""><span><span class="comment">         * ClassPathXMLApplicationContext包含着BeanFactory所提供的一切特征,在这一步骤中将会复用</span> </span></li><li class="alt"><span><span class="comment">         * BeanFactory中的配置文件读取解析及其他功能,这一步之后,ClassPathXmlApplicationContext</span> </span></li><li class=""><span><span class="comment">         * 实际上就已经包含了BeanFactory所提供的功能,也就是可以进行Bean的提取等基础操作了。</span> </span></li><li class="alt"><span><span class="comment">         */</span><span>  </span></span></li><li class=""><span>        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  </span></li><li class="alt"><span>  </span></li><li class=""><span>        <span class="comment">// Prepare the bean factory for use in this context.</span><span>  </span></span></li><li class="alt"><span>        <span class="comment">//对beanFactory进行各种功能填充</span><span>  </span></span></li><li class=""><span>        <span class="comment">/*</span> </span></li><li class="alt"><span><span class="comment">         * @Qualifier与@Autowired等注解正是在这一步骤中增加的支持</span> </span></li><li class=""><span><span class="comment">         */</span><span>  </span></span></li><li class="alt"><span>        prepareBeanFactory(beanFactory);  </span></li><li class=""><span>  </span></li><li class="alt"><span>        <span class="keyword">try</span><span> {  </span></span></li><li class=""><span>            <span class="comment">// Allows post-processing of the bean factory in context subclasses.</span><span>  </span></span></li><li class="alt"><span>            <span class="comment">//子类覆盖方法做额外处理</span><span>  </span></span></li><li class=""><span>            <span class="comment">/*</span> </span></li><li class="alt"><span><span class="comment">             * Spring之所以强大,为世人所推崇,除了它功能上为大家提供了便利外,还有一方面是它的</span> </span></li><li class=""><span><span class="comment">             * 完美架构,开放式的架构让g使用它的程序猿很容易根据业务需要扩展已经存在的功能。这种开放式</span> </span></li><li class="alt"><span><span class="comment">             * 的设计在Spring中随处可见,例如在本例中就提供了一个空的函数实现postProcessBeanFactory来</span> </span></li><li class=""><span><span class="comment">             * 方便程序猿在业务上做进一步扩展</span> </span></li><li class="alt"><span><span class="comment">             */</span><span>  </span></span></li><li class=""><span>            postProcessBeanFactory(beanFactory);  </span></li><li class="alt"><span>  </span></li><li class=""><span>            <span class="comment">// Invoke factory processors registered as beans in the context.</span><span>  </span></span></li><li class="alt"><span>            <span class="comment">//激活各种beanFactory处理器</span><span>  </span></span></li><li class=""><span>            invokeBeanFactoryPostProcessors(beanFactory);  </span></li><li class="alt"><span>  </span></li><li class=""><span>            <span class="comment">// Register bean processors that intercept bean creation.</span><span>  </span></span></li><li class="alt"><span>            <span class="comment">//注册拦截Bean创建的Bean处理器,这里只是注册,真正的调用实在getBean时候</span><span>  </span></span></li><li class=""><span>            registerBeanPostProcessors(beanFactory);  </span></li><li class="alt"><span>  </span></li><li class=""><span>            <span class="comment">// Initialize message source for this context.</span><span>  </span></span></li><li class="alt"><span>            <span class="comment">//为上下文初始化Message源,即不同语言的消息提,国际化处理</span><span>  </span></span></li><li class=""><span>            initMessageSource();  </span></li><li class="alt"><span>  </span></li><li class=""><span>            <span class="comment">// Initialize event multicaster for this context.</span><span>  </span></span></li><li class="alt"><span>            <span class="comment">//初始化应用消息广播器,并放入“applicationEventMulticaster”bean中</span><span>  </span></span></li><li class=""><span>            initApplicationEventMulticaster();  </span></li><li class="alt"><span>  </span></li><li class=""><span>            <span class="comment">// Initialize other special beans in specific context subclasses.</span><span>  </span></span></li><li class="alt"><span>            <span class="comment">//留给子类来初始化其它的Bean</span><span>  </span></span></li><li class=""><span>            onRefresh();  </span></li><li class="alt"><span>  </span></li><li class=""><span>            <span class="comment">// Check for listener beans and register them.</span><span>  </span></span></li><li class="alt"><span>            <span class="comment">//在所有注册的bean中查找Listener bean,注册到消息广播器中</span><span>  </span></span></li><li class=""><span>            registerListeners();  </span></li><li class="alt"><span>  </span></li><li class=""><span>            <span class="comment">// Instantiate all remaining (non-lazy-init) singletons.</span><span>  </span></span></li><li class="alt"><span>            <span class="comment">//初始化剩下的单实例(非惰性的)</span><span>  </span></span></li><li class=""><span>            finishBeanFactoryInitialization(beanFactory);  </span></li><li class="alt"><span>  </span></li><li class=""><span>            <span class="comment">// Last step: publish corresponding event.</span><span>  </span></span></li><li class="alt"><span>            <span class="comment">//完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出</span><span>  </span></span></li><li class=""><span>            <span class="comment">//ContextRefreshEvent通知别人</span><span>  </span></span></li><li class="alt"><span>            finishRefresh();  </span></li><li class=""><span>        }  </span></li><li class="alt"><span>  </span></li><li class=""><span>        <span class="keyword">catch</span><span> (BeansException ex) {  </span></span></li><li class="alt"><span>            <span class="keyword">if</span><span> (logger.isWarnEnabled()) {  </span></span></li><li class=""><span>                logger.warn(<span class="string">"Exception encountered during context initialization - "</span><span> +  </span></span></li><li class="alt"><span>                        <span class="string">"cancelling refresh attempt: "</span><span> + ex);  </span></span></li><li class=""><span>            }  </span></li><li class="alt"><span>  </span></li><li class=""><span>            <span class="comment">// Destroy already created singletons to avoid dangling resources.</span><span>  </span></span></li><li class="alt"><span>            destroyBeans();  </span></li><li class=""><span>  </span></li><li class="alt"><span>            <span class="comment">// Reset 'active' flag.</span><span>  </span></span></li><li class=""><span>            cancelRefresh(ex);  </span></li><li class="alt"><span>  </span></li><li class=""><span>            <span class="comment">// Propagate exception to caller.</span><span>  </span></span></li><li class="alt"><span>            <span class="keyword">throw</span><span> ex;  </span></span></li><li class=""><span>        }  </span></li><li class="alt"><span>    }  </span></li><li class=""><span>}  </span></li></ol></div><pre code_snippet_id="1761056" snippet_file_name="blog_20160713_4_6581187" name="code" class="java" style="display: none;">	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			//准备刷新的上下文 环境
			/*
			 * 初始化前的准备工作,例如对系统属性或者环境变量进行准备及验证。
			 * 在某种情况下项目的使用需要读取某些系统变量,而这个变量的设置很可能会影响着系统
			 * 的正确性,那么ClassPathXmlApplicationContext为我们提供的这个准备函数就显得非常必要,
			 * 它可以在Spring启动的时候提前对必须的变量进行存在性验证。
			 */
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			//初始化BeanFactory,并进行XML文件读取
			/*
			 * ClassPathXMLApplicationContext包含着BeanFactory所提供的一切特征,在这一步骤中将会复用
			 * BeanFactory中的配置文件读取解析及其他功能,这一步之后,ClassPathXmlApplicationContext
			 * 实际上就已经包含了BeanFactory所提供的功能,也就是可以进行Bean的提取等基础操作了。
			 */
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			//对beanFactory进行各种功能填充
			/*
			 * @Qualifier与@Autowired等注解正是在这一步骤中增加的支持
			 */
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				//子类覆盖方法做额外处理
				/*
				 * Spring之所以强大,为世人所推崇,除了它功能上为大家提供了便利外,还有一方面是它的
				 * 完美架构,开放式的架构让g使用它的程序猿很容易根据业务需要扩展已经存在的功能。这种开放式
				 * 的设计在Spring中随处可见,例如在本例中就提供了一个空的函数实现postProcessBeanFactory来
				 * 方便程序猿在业务上做进一步扩展
				 */
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				//激活各种beanFactory处理器
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				//注册拦截Bean创建的Bean处理器,这里只是注册,真正的调用实在getBean时候
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				//为上下文初始化Message源,即不同语言的消息提,国际化处理
				initMessageSource();

				// Initialize event multicaster for this context.
				//初始化应用消息广播器,并放入“applicationEventMulticaster”bean中
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				//留给子类来初始化其它的Bean
				onRefresh();

				// Check for listener beans and register them.
				//在所有注册的bean中查找Listener bean,注册到消息广播器中
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				//初始化剩下的单实例(非惰性的)
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				//完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出
				//ContextRefreshEvent通知别人
				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;
			}
		}
	}</pre><br>
<p><span style="font-size:18px"><strong>3.环境准备</strong></span></p>
<p><span style="font-size:18px"><span style="font-size:12px">prepareRefresh函数主要是做些准备工作,例如对系统属性及环境变量的初始化及验证</span></span></p>
<p><span style="font-size:18px"><span style="font-size:12px"></span></span></p>
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" target="_blank">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" target="_blank">copy</a><div style="position: absolute; left: 762px; top: 3723px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_5" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_5" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=5&width=18&height=18" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" target="_blank">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;" target="_blank">?</a></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> prepareRefresh() {  </span></span></li><li class=""><span>    <span class="keyword">this</span><span>.startupDate = System.currentTimeMillis();  </span></span></li><li class="alt"><span>  </span></li><li class=""><span>    <span class="keyword">synchronized</span><span> (</span><span class="keyword">this</span><span>.activeMonitor) {  </span></span></li><li class="alt"><span>        <span class="keyword">this</span><span>.active = </span><span class="keyword">true</span><span>;  </span></span></li><li class=""><span>    }  </span></li><li class="alt"><span>  </span></li><li class=""><span>    <span class="keyword">if</span><span> (logger.isInfoEnabled()) {  </span></span></li><li class="alt"><span>        logger.info(<span class="string">"Refreshing "</span><span> + </span><span class="keyword">this</span><span>);  </span></span></li><li class=""><span>    }  </span></li><li class="alt"><span>  </span></li><li class=""><span>    <span class="comment">// Initialize any placeholder property sources in the context environment</span><span>  </span></span></li><li class="alt"><span>    <span class="comment">//留给子类覆盖</span><span>  </span></span></li><li class=""><span>    initPropertySources();  </span></li><li class="alt"><span>  </span></li><li class=""><span>    <span class="comment">// Validate that all properties marked as required are resolvable</span><span>  </span></span></li><li class="alt"><span>    <span class="comment">// see ConfigurablePropertyResolver#setRequiredProperties</span><span>  </span></span></li><li class=""><span>    getEnvironment().validateRequiredProperties();  </span></li><li class="alt"><span>}  </span></li></ol></div><pre code_snippet_id="1761056" snippet_file_name="blog_20160713_5_1357717" name="code" class="java" style="display: none;">	protected void prepareRefresh() {
		this.startupDate = System.currentTimeMillis();

		synchronized (this.activeMonitor) {
			this.active = true;
		}

		if (logger.isInfoEnabled()) {
			logger.info("Refreshing " + this);
		}

		// Initialize any placeholder property sources in the context environment
		//留给子类覆盖
		initPropertySources();

		// Validate that all properties marked as required are resolvable
		// see ConfigurablePropertyResolver#setRequiredProperties
		getEnvironment().validateRequiredProperties();
	}</pre><br>
这个函数看似没有社么用,因为最后两句代码才是关键,但是却没有什么逻辑处理,initPropertySources是空的,没有什么逻辑,而getEnvironment().validaterequiredProperties也因为没有需要验证的属性而没有做任何处理。其实这个函数用好了作用还是挺大的,那么该怎么用呢,我们先探索下各个函数的作用。
<p></p>
<p><span style="font-size:18px"><span style="font-size:12px">(1)initPropertySources证符合Spring的开放式结构设计,给用户最大扩展Spring的能力。用户可以根据自身的需要重写initPropertySourece方法,并在方法中进行个性化的属性处理及设置。</span></span></p>
<p><span style="font-size:18px"><span style="font-size:12px">(2)validateRequiredProperties则是对属性进行验证,那么如何验证呢?举个融合两句代码的小例子来理解。</span></span></p>
<p><span style="font-size:18px"><span style="font-size:12px">例如现在有这样一个需求,工程在运行过程中用到的某个设置(例如VAR)是从系统环境变量中取得的,而如果用户没有在系统环境变量中配置这个参数,,工程不会工作。这一要求也许有各种各样的解决办法,在Spring中可以这么做,可以直接修改Spring的源码,例如修改ClassPathXmlApplicationContext.淡然,最好的办法是对源码进行扩展,可以自定义类:</span></span></p>
<p><span style="font-size:18px"><strong></strong></span></p>
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" target="_blank">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" target="_blank">copy</a><div style="position: absolute; left: 762px; top: 4484px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_6" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_6" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=6&width=18&height=18" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" target="_blank">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;" target="_blank">?</a></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> MyClassPathXmlApplicationContext </span><span class="keyword">extends</span><span> ClassPathXmlApplicationContext{  </span></span></li><li class=""><span>      <span class="keyword">public</span><span> MyClassPathXmlApplicationContext(String.. configLocations){  </span></span></li><li class="alt"><span>            <span class="keyword">super</span><span>(configLocations);  </span></span></li><li class=""><span>       }  </span></li><li class="alt"><span>       <span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> initPropertySources(){  </span></span></li><li class=""><span>             <span class="comment">//添加验证要求</span><span>  </span></span></li><li class="alt"><span>             getEnvironment().setRequiredProterties(<span class="string">"VAR"</span><span>);  </span></span></li><li class=""><span>       }  </span></li><li class="alt"><span>}  </span></li></ol></div><pre code_snippet_id="1761056" snippet_file_name="blog_20160713_6_2263571" name="code" class="java" style="display: none;">public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{
      public MyClassPathXmlApplicationContext(String.. configLocations){
            super(configLocations);
       }
       protected void initPropertySources(){
             //添加验证要求
             getEnvironment().setRequiredProterties("VAR");
       }
}</pre><br>
<span style="font-size:12px">自定义了继承自ClassPathXmlApplicationContext的MyClassPathXmlApplicationContext,并重写了initPropertySources方法,在方法中添加了个性化需求,那么在验证的时候也就是程序走到getEnvironment().validateRequiredProperties()代码的时候,如果系统并没有检测到对应VAR的环境变量,将抛出异常。当然我们还需要在使用的时候替换掉原有的ClassPathXmlApplicationContext:</span>
<p></p>
<p><span style="font-size:18px"><span style="font-size:12px"></span></span></p>
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" target="_blank">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" target="_blank">copy</a><div style="position: absolute; left: 762px; top: 4855px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_7" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_7" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=7&width=18&height=18" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" target="_blank">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;" target="_blank">?</a></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">void</span><span> main(Stirng[] args){  </span></span></li><li class=""><span>      ApplicationContext bf = <span class="keyword">new</span><span> MyClassPathXmlApplicationContext(</span><span class="string">"myTest.xml"</span><span>);  </span></span></li><li class="alt"><span>      User user = (User)bf.getBean(<span class="string">"testBean"</span><span>);  </span></span></li><li class=""><span>}  </span></li></ol></div><pre code_snippet_id="1761056" snippet_file_name="blog_20160713_7_4357122" name="code" class="java" style="display: none;">public static void main(Stirng[] args){
      ApplicationContext bf = new MyClassPathXmlApplicationContext("myTest.xml");
      User user = (User)bf.getBean("testBean");
}</pre><span style="font-size:18px"><strong><br>
</strong></span><span style="font-size:18px"><strong>4.加载BeanFactory</strong></span>
<p></p>
<p><span style="font-size:18px"><span style="font-size:12px">obtainFreshBeanFactory方法从字面理解是获取beanFactory.ApplicationContext是对BeanFactory的扩展,在其基础上添加了大量的基础应用,<span style="font-size:18px"><span style="font-size:12px">obtainFreshBeanFactory</span></span>正式实现beanFactory的地方,经过这个函数后ApplicationContext就有了BeanFactory的全部功能。</span></span></p>
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" target="_blank">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" target="_blank">copy</a><div style="position: absolute; left: 762px; top: 5136px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_8" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_8" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=8&width=18&height=18" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" target="_blank">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;" target="_blank">?</a></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">protected</span><span> ConfigurableListableBeanFactory obtainFreshBeanFactory() {  </span></span></li><li class=""><span>    <span class="comment">//初始化BeanFactory,并进行XML文件读取,并将得到的BeanFactory记录在当前实体的属性中</span><span>  </span></span></li><li class="alt"><span>    refreshBeanFactory();  </span></li><li class=""><span>    <span class="comment">//返回 当前实体的beanFactory属性</span><span>  </span></span></li><li class="alt"><span>    ConfigurableListableBeanFactory beanFactory = getBeanFactory();  </span></li><li class=""><span>    <span class="keyword">if</span><span> (logger.isDebugEnabled()) {  </span></span></li><li class="alt"><span>        logger.debug(<span class="string">"Bean factory for "</span><span> + getDisplayName() + </span><span class="string">": "</span><span> + beanFactory);  </span></span></li><li class=""><span>    }  </span></li><li class="alt"><span>    <span class="keyword">return</span><span> beanFactory;  </span></span></li><li class=""><span>}  </span></li></ol></div><pre code_snippet_id="1761056" snippet_file_name="blog_20160713_8_1674927" name="code" class="java" style="display: none;">	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		//初始化BeanFactory,并进行XML文件读取,并将得到的BeanFactory记录在当前实体的属性中
		refreshBeanFactory();
		//返回 当前实体的beanFactory属性
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}</pre><br>
方法中将核心实现委托给了refreshBeanFactory:
<p></p>
<p><span style="font-size:18px"><span style="font-size:12px"></span></span></p>
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" target="_blank">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" target="_blank">copy</a><div style="position: absolute; left: 762px; top: 5455px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_9" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_9" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=9&width=18&height=18" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" target="_blank">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;" target="_blank">?</a></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">protected</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">void</span><span> refreshBeanFactory() </span><span class="keyword">throws</span><span> BeansException {  </span></span></li><li class=""><span>    <span class="keyword">if</span><span> (hasBeanFactory()) {  </span></span></li><li class="alt"><span>        destroyBeans();  </span></li><li class=""><span>        closeBeanFactory();  </span></li><li class="alt"><span>    }  </span></li><li class=""><span>    <span class="keyword">try</span><span> {  </span></span></li><li class="alt"><span>        <span class="comment">//创建DefaultListableBeanFactory</span><span>  </span></span></li><li class=""><span>        <span class="comment">/*</span> </span></li><li class="alt"><span><span class="comment">         * 以前我们分析BeanFactory的时候,不知道是否还有印象,声明方式为:BeanFactory bf = </span> </span></li><li class=""><span><span class="comment">         * new XmlBeanFactory("beanFactoryTest.xml"),其中的XmlBeanFactory继承自DefaulltListableBeanFactory;</span> </span></li><li class="alt"><span><span class="comment">         * 并提供了XmlBeanDefinitionReader类型的reader属性,也就是说DefaultListableBeanFactory是容器的基础。必须</span> </span></li><li class=""><span><span class="comment">         * 首先要实例化。</span> </span></li><li class="alt"><span><span class="comment">         */</span><span>  </span></span></li><li class=""><span>        DefaultListableBeanFactory beanFactory = createBeanFactory();  </span></li><li class="alt"><span>        <span class="comment">//为了序列化指定id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象</span><span>  </span></span></li><li class=""><span>        beanFactory.setSerializationId(getId());  </span></li><li class="alt"><span>        <span class="comment">//定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖以及设置</span><span>  </span></span></li><li class=""><span>        <span class="comment">//@Autowired和Qualifier注解解析器QualifierAnnotationAutowireCandidateResolver</span><span>  </span></span></li><li class="alt"><span>        customizeBeanFactory(beanFactory);  </span></li><li class=""><span>        <span class="comment">//加载BeanDefiniton</span><span>  </span></span></li><li class="alt"><span>        loadBeanDefinitions(beanFactory);  </span></li><li class=""><span>        <span class="keyword">synchronized</span><span> (</span><span class="keyword">this</span><span>.beanFactoryMonitor) {  </span></span></li><li class="alt"><span>            <span class="comment">//使用全局变量记录BeanFactory实例。</span><span>  </span></span></li><li class=""><span>            <span class="comment">//因为DefaultListableBeanFactory类型的变量beanFactory是函数内部的局部变量,</span><span>  </span></span></li><li class="alt"><span>            <span class="comment">//所以要使用全局变量记录解析结果</span><span>  </span></span></li><li class=""><span>            <span class="keyword">this</span><span>.beanFactory = beanFactory;  </span></span></li><li class="alt"><span>        }  </span></li><li class=""><span>    }  </span></li><li class="alt"><span>    <span class="keyword">catch</span><span> (IOException ex) {  </span></span></li><li class=""><span>        <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> ApplicationContextException(</span><span class="string">"I/O error parsing bean definition source for "</span><span> + getDisplayName(), ex);  </span></span></li><li class="alt"><span>    }  </span></li><li class=""><span>}  </span></li></ol></div><pre code_snippet_id="1761056" snippet_file_name="blog_20160713_9_4848273" name="code" class="java" style="display: none;">	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			//创建DefaultListableBeanFactory
			/*
			 * 以前我们分析BeanFactory的时候,不知道是否还有印象,声明方式为:BeanFactory bf = 
			 * new XmlBeanFactory("beanFactoryTest.xml"),其中的XmlBeanFactory继承自DefaulltListableBeanFactory;
			 * 并提供了XmlBeanDefinitionReader类型的reader属性,也就是说DefaultListableBeanFactory是容器的基础。必须
			 * 首先要实例化。
			 */
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			//为了序列化指定id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象
			beanFactory.setSerializationId(getId());
			//定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖以及设置
			//@Autowired和Qualifier注解解析器QualifierAnnotationAutowireCandidateResolver
			customizeBeanFactory(beanFactory);
			//加载BeanDefiniton
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				//使用全局变量记录BeanFactory实例。
				//因为DefaultListableBeanFactory类型的变量beanFactory是函数内部的局部变量,
				//所以要使用全局变量记录解析结果
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}</pre><br>
1)定制BeanFactory
<p></p>
<p><span style="font-size:18px"><span style="font-size:12px"><strong>customizeBeanFactor方法在基本容器的基础上,增加了是否允许覆盖是否允许扩展的设置并提供了主机@Qualifierh额@Autowired支持。</strong></span></span></p>
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" target="_blank">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" target="_blank">copy</a><div style="position: absolute; left: 762px; top: 6205px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_10" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_10" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=10&width=18&height=18" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" target="_blank">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;" target="_blank">?</a></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> customizeBeanFactory(DefaultListableBeanFactory beanFactory) {  </span></span></li><li class=""><span>        <span class="comment">//如果属性sllowBeanDefinitionOverring不为空,设置给beanFactory对象相应属性,</span><span>  </span></span></li><li class="alt"><span>        <span class="comment">//此属性的含义:是否允许覆盖同名称的不同定义的对象</span><span>  </span></span></li><li class=""><span>        <span class="keyword">if</span><span> (</span><span class="keyword">this</span><span>.allowBeanDefinitionOverriding != </span><span class="keyword">null</span><span>) {  </span></span></li><li class="alt"><span>            beanFactory.setAllowBeanDefinitionOverriding(<span class="keyword">this</span><span>.allowBeanDefinitionOverriding);  </span></span></li><li class=""><span>        }  </span></li><li class="alt"><span>        <span class="comment">//如果属性allowCircularReferences不为空,设置给beanFactory对象相应属性,</span><span>  </span></span></li><li class=""><span>        <span class="comment">//此属性的含义:是否允许循环依赖</span><span>  </span></span></li><li class="alt"><span>        <span class="keyword">if</span><span> (</span><span class="keyword">this</span><span>.allowCircularReferences != </span><span class="keyword">null</span><span>) {  </span></span></li><li class=""><span>            beanFactory.setAllowCircularReferences(<span class="keyword">this</span><span>.allowCircularReferences);  </span></span></li><li class="alt"><span>        }  </span></li><li class=""><span>        <span class="comment">//用于@Qualifier和@Autowired</span><span>  </span></span></li><li class="alt"><span>        beanFactory.setAutowireCandidateResolver(<span class="keyword">new</span><span> QualifierAnnotationAutowireCandidateResolver());  </span></span></li><li class=""><span>    }  </span></li></ol></div><pre code_snippet_id="1761056" snippet_file_name="blog_20160713_10_3561518" name="code" class="java" style="display: none;">protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
		//如果属性sllowBeanDefinitionOverring不为空,设置给beanFactory对象相应属性,
		//此属性的含义:是否允许覆盖同名称的不同定义的对象
		if (this.allowBeanDefinitionOverriding != null) {
			beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		//如果属性allowCircularReferences不为空,设置给beanFactory对象相应属性,
		//此属性的含义:是否允许循环依赖
		if (this.allowCircularReferences != null) {
			beanFactory.setAllowCircularReferences(this.allowCircularReferences);
		}
		//用于@Qualifier和@Autowired
		beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
	}</pre><br>
对于允许覆盖和允许依赖的设置这里只判断了是否为空,如果不为空姚进行设置,但是并没有看到在哪里设置,究竟在哪里设置?
<p></p>
<p><span style="font-size:18px"><span style="font-size:12px"><strong>这时候还是利用Spring的可扩展性,使用子类覆盖的方法,例如:</strong></span></span></p>
<p><span style="font-size:18px"><span style="font-size:12px"><strong><br>
</strong></span></span></p>
<p><span style="font-size:18px"><span style="font-size:12px"><strong></strong></span></span></p>
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" target="_blank">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" target="_blank">copy</a><div style="position: absolute; left: 762px; top: 6666px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_11" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_11" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=11&width=18&height=18" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" target="_blank">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;" target="_blank">?</a></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> MyClassPathXmlApplicationContext </span><span class="keyword">extends</span><span> ClassPathXmlApplicationContext{  </span></span></li><li class=""><span>      ... ...  </span></li><li class="alt"><span>      <span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> customizeBeanFactory(DefaultListableBeanFactory beanFactory){  </span></span></li><li class=""><span>            <span class="keyword">super</span><span>.setAllowBeanDefinitionOverriding(fa;se);  </span></span></li><li class="alt"><span>            <span class="keyword">super</span><span>.setAllowCircularReferences(</span><span class="keyword">false</span><span>);  </span></span></li><li class=""><span>            <span class="keyword">super</span><span>.customizeBeanFactory(beanFactory);  </span></span></li><li class="alt"><span>      }  </span></li><li class=""><span>}  </span></li></ol></div><pre code_snippet_id="1761056" snippet_file_name="blog_20160713_11_8686711" name="code" class="java" style="display: none;">public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{
      ... ...
      protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory){
            super.setAllowBeanDefinitionOverriding(fa;se);
            super.setAllowCircularReferences(false);
            super.customizeBeanFactory(beanFactory);
      }
}</pre><br>
Spring使用了QualifierAnnotationAutowireCandidateResolver这个解析器后,Spring就支持注解方式的注入了,
<p></p>
<p><span style="font-size:18px"><span style="font-size:12px"><strong>在以前分析根据类型注入的时候,我们说过解析autowire类型时首先会调用方法:</strong></span></span></p>
<p><span style="font-size:18px"><span style="font-size:12px"><strong>Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);</strong></span></span></p>
<p><span style="font-size:18px"><span style="font-size:12px"><strong>因此,在QualifierAnnotationAutowireCandidatResolver中一定会提供解析Autowire注解的方法:</strong></span></span></p>
<p><span style="font-size:18px"><span style="font-size:12px"><strong></strong></span></span></p>
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" target="_blank">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" target="_blank">copy</a><div style="position: absolute; left: 762px; top: 7054px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_12" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_12" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=12&width=18&height=18" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" target="_blank">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;" target="_blank">?</a></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">public</span><span> Object getSuggestedValue(DependencyDescriptor descriptor) {  </span></span></li><li class=""><span>    Object value = findValue(descriptor.getAnnotations());  </span></li><li class="alt"><span>    <span class="keyword">if</span><span> (value == </span><span class="keyword">null</span><span>) {  </span></span></li><li class=""><span>        MethodParameter methodParam = descriptor.getMethodParameter();  </span></li><li class="alt"><span>        <span class="keyword">if</span><span> (methodParam != </span><span class="keyword">null</span><span>) {  </span></span></li><li class=""><span>            value = findValue(methodParam.getMethodAnnotations());  </span></li><li class="alt"><span>        }  </span></li><li class=""><span>    }  </span></li><li class="alt"><span>    <span class="keyword">return</span><span> value;  </span></span></li><li class=""><span>}  </span></li></ol></div><pre code_snippet_id="1761056" snippet_file_name="blog_20160713_12_2624209" name="code" class="java" style="display: none;">	public Object getSuggestedValue(DependencyDescriptor descriptor) {
		Object value = findValue(descriptor.getAnnotations());
		if (value == null) {
			MethodParameter methodParam = descriptor.getMethodParameter();
			if (methodParam != null) {
				value = findValue(methodParam.getMethodAnnotations());
			}
		}
		return value;
	}
</pre>
<p><br>
</p>
<p><span style="font-size:18px"><strong>加载beanDefinition</strong></span></p>
<p><span style="font-size:12px">在第一步中提到了将ClassPathXmlApplicationContext与XMLBeanFactory创建的对比,除了初始化DefaultListableBeanFactory外,还需要XmlBeanDefinitionReader来读取XML,那么在loadBeanDefinitions方法中首先要做的就是初始化XmlBeanDefinitonReader.</span></p>
<p><span style="font-size:12px"></span></p><div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" target="_blank">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" target="_blank">copy</a><div style="position: absolute; left: 762px; top: 7443px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_13" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_13" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=13&width=18&height=18" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" target="_blank">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;" target="_blank">?</a></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> loadBeanDefinitions(DefaultListableBeanFactory beanFactory) </span><span class="keyword">throws</span><span> BeansException, IOException {  </span></span></li><li class=""><span>    <span class="comment">// Create a new XmlBeanDefinitionReader for the given BeanFactory.</span><span>  </span></span></li><li class="alt"><span>    XmlBeanDefinitionReader beanDefinitionReader = <span class="keyword">new</span><span> XmlBeanDefinitionReader(beanFactory);  </span></span></li><li class=""><span>  </span></li><li class="alt"><span>    <span class="comment">// Configure the bean definition reader with this context's</span><span>  </span></span></li><li class=""><span>    <span class="comment">// resource loading environment.</span><span>  </span></span></li><li class="alt"><span>    beanDefinitionReader.setEnvironment(<span class="keyword">this</span><span>.getEnvironment());  </span></span></li><li class=""><span>    beanDefinitionReader.setResourceLoader(<span class="keyword">this</span><span>);  </span></span></li><li class="alt"><span>    beanDefinitionReader.setEntityResolver(<span class="keyword">new</span><span> ResourceEntityResolver(</span><span class="keyword">this</span><span>));  </span></span></li><li class=""><span>  </span></li><li class="alt"><span>    <span class="comment">// Allow a subclass to provide custom initialization of the reader,</span><span>  </span></span></li><li class=""><span>    <span class="comment">// then proceed with actually loading the bean definitions.</span><span>  </span></span></li><li class="alt"><span>    initBeanDefinitionReader(beanDefinitionReader);  </span></li><li class=""><span>    loadBeanDefinitions(beanDefinitionReader);  </span></li><li class="alt"><span>}  </span></li></ol></div><pre code_snippet_id="1761056" snippet_file_name="blog_20160713_13_4346172" name="code" class="java" style="display: none;">	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}</pre><br>
在初始化了DefaultListableBeanFactory和XmlBeanDefinitionReader后,就可以进行配置文件的读取了。<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" target="_blank">view plain</a><span data-mod="popu_168"> <a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" target="_blank">copy</a><div style="position: absolute; left: 762px; top: 7852px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_14" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_14" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=14&width=18&height=18" wmode="transparent"></div></span><span data-mod="popu_169"> <a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;" target="_blank">print</a></span><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;" target="_blank">?</a></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> loadBeanDefinitions(XmlBeanDefinitionReader reader) </span><span class="keyword">throws</span><span> BeansException, IOException {  </span></span></li><li class=""><span>    Resource[] configResources = getConfigResources();  </span></li><li class="alt"><span>    <span class="keyword">if</span><span> (configResources != </span><span class="keyword">null</span><span>) {  </span></span></li><li class=""><span>        reader.loadBeanDefinitions(configResources);  </span></li><li class="alt"><span>    }  </span></li><li class=""><span>    String[] configLocations = getConfigLocations();  </span></li><li class="alt"><span>    <span class="keyword">if</span><span> (configLocations != </span><span class="keyword">null</span><span>) {  </span></span></li><li class=""><span>        reader.loadBeanDefinitions(configLocations);  </span></li><li class="alt"><span>    }  </span></li><li class=""><span>}  </span></li></ol></div><pre code_snippet_id="1761056" snippet_file_name="blog_20160713_14_758905" name="code" class="java" style="display: none;">	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}</pre><br>
因为在XmlBeanDefinitionReader中已经将之前初始化的DefaultListableBeanFactory注册进去了,所以XmlBeanDefinitionReader所读取的BeanDefinitionHolder都会注册到DefinitionListableBeanFactory中,也就是经过这个步骤,DefaultListableBeanFactory的变量beanFactory已经包含了所有解析好的配置。<br>
<p></p>
<p></p>
<p></p>
   
</div>

猜你喜欢

转载自blog.csdn.net/noob9527/article/details/76522672