Spring源码学习第二节

IOC容器初始化过程

发起是上一节课,的refresh()来启动的。启动会进行,BeanDefinition的Resouce定位、载入和注册三个基本过程。(spring把三个过程分开了,在不同的模块完成,然后组合起来,这样就可以更加灵活的剪裁和扩展)。


1.Resource定位,它由ResourceLoader通过统一的Resource接口完成。

      具体实现在上一节写过代码。获得配置文件的resource,通过reader将resource和factory结合。这样提现出applicationContext的好处了。有具体的FileSystemXmlApplicationContext这就是读取系统文件等。

     先看一下该类继承那些类。

   

 由于已经继承了AbstractXmlApplicationContext类(最上层是Loader),所以具备了resourceLoader读入BeanDefinition的能力。

  FileSystemXmlApplicationContext的构造器允许传入string (Resource的文件路径)或数组(多个),已经其他IOC。refresh参数,是指定是否刷新将beanDefinition载入。

   

protected Resource getResourceByPath(String path) {
		if (path != null && path.startsWith("/")) {
			path = path.substring(1);
		}
		return new FileSystemResource(path);
	}
这个方法是在 BeanDefinitionReader类的loadBeanDefinition方法(使用的是模板模式,具体实现是由子类来完成的,也就是这里的getResourceByPath方法实现的)中调用的。

     那么FileSystemXmlApplicationContext类是在父类AbstractRefreshableAppicationContext类中,定义BeanDefinitionReader从而完成bean读入。

    AbstractRefreshableAppicationContext的 refreshBeanFactory方法。它被FileSystemXmlApplicationContext构造方法中refresh()调用。

   

protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {                                           //如果已经建立了BeanFactory,则销毁并关闭beanFactory
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();  //通过此方法构建了一个ioc容器来供applicationContext使用
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);    //载入BeanDefinition 启动
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
createBeanFactory,getInternalParentBeanFactory是在AbstractAppicationContext实现获取双亲的IOC容器。

protected DefaultListableBeanFactory createBeanFactory() {
		return new DefaultListableBeanFactory(getInternalParentBeanFactory());
	}
BeanDefinitionReader是顶层父类,重载了很多loadBeanDefinitions方法。实现是在AbstractBeanDefinitionReader类。但是最终调用的还是一个方法。

	public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
		ResourceLoader resourceLoader = getResourceLoader();   //使用的是DefaultResourceLoader
		if (resourceLoader == null) {
			throw new BeanDefinitionStoreException(
					"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
		}
                       //这里对Resource的路径解析。比如设定的各种ant格式的路径定义,得到需要的resource集合
		if (resourceLoader instanceof ResourcePatternResolver) {
			// Resource pattern matching available.
			try {
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				int loadCount = loadBeanDefinitions(resources);
				if (actualResources != null) {
					for (Resource resource : resources) {
						actualResources.add(resource);
					}
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
				}
				return loadCount;
			}
			catch (IOException ex) {
				throw new BeanDefinitionStoreException(
						"Could not resolve bean definition resource pattern [" + location + "]", ex);
			}
		}
		else {
			// 同样是完成resource定位
			Resource resource = resourceLoader.getResource(location);
			int loadCount = loadBeanDefinitions(resource);
			if (actualResources != null) {
				actualResources.add(resource);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
			}
			return loadCount;
		}
	}
getResource方法  看DefaultResourceLoader是如何实现的。

	public Resource getResource(String location) {
		Assert.notNull(location, "Location must not be null");
		if (location.startsWith("/")) {
			return getResourceByPath(location);
		}   //如果路径带有classpath,进行下面的处理
		else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
			return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
		}
		else {
			try {
				// Try to parse the location as a URL...   处理URL定位
				URL url = new URL(location);
				return new UrlResource(url);
			}
			catch (MalformedURLException ex) {
				// No URL -> resolve as resource path.   如果都不是就交给子类实现 getResourceByPath方法  我们这里就是FileSystemXXX.实现
                                                              return getResourceByPath(location);
}}}


2.BeanDefinition的载入,将用户定义好的bean表示成IOC的数据结构(BeanDefinition)。

   通过HashMap<BeanDefinition>来维护的。

   以DefaultListableBeanFactory为例,看IOC如何载入。

    IOC初始化是调用refresh(),该方法是在父类,AbstractAppicationContext类中实现的。其中包含:BeanFactory更新、MessageSource和PostProcessor的注册。

   

           public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// 子类中启动refreshBeanFactory()的地方
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// 设置BeanFactory的后置处理
				postProcessBeanFactory(beanFactory);

				// 调用BeanFactory的后处理器,这些后处理器是在Bean定义中向容器注册
				invokeBeanFactoryPostProcessors(beanFactory);

				// 注册Bean的后处理器,在Bean创建过程中调用
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster(机制) for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.初始化其他的特殊bean
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons. 初始化所有的单件
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.  发布容器事件,结束refresh过程
				finishRefresh();
			}

			catch (BeansException ex) {
				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;
			}
		}
	}

之后看,AbstractRefreshableApplicationContext的refreshBeanFactory()方法(该方法在前面提到过)

	protected final void refreshBeanFactory() throws BeansException {
      //是否已经存在IOC容器,如果存在销毁关闭。保证refresh之后是新的,更新bean
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
                //创建IOC容器
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
                //启动对BeanDefinition的载入
			loadBeanDefinitions(beanFactory);  //看参数,下面介绍存在一个重载方法,才是真正使用的loadBeanDefinition
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
上面讲的loadBeanDefinitions方法,是在AbstractXmlApplicationContext中实现,(存在2个方法,重载,另一个),初始化了读取器XmlBeanDefinitionReader。

该方法就是实现了reader(beanfactory),然后将beanDefinition设置到Factory

最终还是reader获取了resource然后进行一个配置的。所以最后的载入还是看Reader

AbstractBeanDefinitionReader ,已经为BeanDefinition做好了准备。我们调用的就是这个类的loadBeanDefinitions方法。

public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {  //这里是resource...,是多个文件。
		Assert.notNull(resources, "Resource array must not be null");
		int counter = 0;
		for (Resource resource : resources) {
                     //这里的load方法,就是后面我们在子类重写的方法
			counter += loadBeanDefinitions(resource);
		}
		return counter;
	}
具体的读入方式,看子类。比如XmlBeanDefinitionReader。就继承了上面的Reader。并重写了方法。

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}
继续调用的就是读入xml的流然后进行处理了。之后是由BeanDefinitionParserDelegate完成。

之后就是如何读取xml然后进行处理的流程。如何按照spring的Bean语义要求进行解析转化成内部数据结构,代码较多。这我放在下一节中


3.向IOC容器注册BeanDefinition。调用BeanDefinitionRegistry接口来实现的。注入到一个Map中,进行管理。

不包含bean依赖注入的实现。它与载入是两个独立的过程。

依赖注入一般发生在第一次通过getBean获取Bean,或者设置lazyinit属性。(是否想起了hibernate的懒加载?)

此时BeanDefinition信息以及在容器简历自己的数据结构,和表示。但还不能在容器直接使用,需要注册。

在DefaultListableBeanFactory中,定义了MAP

/** Map of bean definition objects, keyed by bean name */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);


注册的步骤:

1.在DefaultListableBeanFactory实现了 BeanDefinitionRegistry的接口。这个接口就是来注册的。其实很简单,就是将BeanDefinition设置到map中,如果遇到同名的BeanDefinition,根据allowBeanDefinitionOver配置来完成的。

XmlBeanDefinitionReader,通过registerBeanDefinitions(Document doc, Resource resource)方法调用。BeanDefinitionDocumentReader的registerBeanDefinitions方法



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值