Spring 源码学习 - ClassPathXmlApplicationContext

众所周知,Spring以其强大而又灵活的IoC管理功能著称。IoC本质上是通过依赖注入DI的方式实现组件之间的解耦。其实在DI模式下,一个关键性的角色是装配器(assembler)。应用程序的组件A在引用别的组件B的时候不用通过new来创建,而是依赖一个第三方的装配器创建好B,然后再通过setter或者constructor来注入给A,这样A只管用B的接口,而不需要知道B的存在,从而实现了A与B的解耦。也实现了面向抽象(接口)编程。

Spring框架里面谁来充当这个assembler的角色呢?是BeanFactory。Spring提供了品种繁多的BeanFactory,共用户在不同场合下使用。我们通常更多的是使用它的子接口ApplicationContext。大致上分了三类:Java Application,Web Application 和 Portlet Application。

本文通过一个简单的例子( http://svn.springbyexample.org/core/basic-dependency-injection/)来看看ClassPathXmlApplicationContext的调用和执行顺序图(用MaintainJ生成的):

Spring 源码学习 - ClassPathXmlApplicationContext_第1张图片

上图的init代表执行构造函数。上图表达了下面这句话:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/application-context.xml");

再看看类图:

Spring 源码学习 - ClassPathXmlApplicationContext_第2张图片

再细致的看下去,分解StandardEnvironment的构建过程(可以看出是解析各种属性的过程):

Spring 源码学习 - ClassPathXmlApplicationContext_第3张图片

属性都load好了,环境也构建好了,那么Bean的实例在哪里创建的呢?关键得看DefaultListableBeanFactory:

Spring 源码学习 - ClassPathXmlApplicationContext_第4张图片

这里面关键是看registerSingleton函数,它负责把bean缓存到singletonObjects (private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>();)
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
		Assert.notNull(beanName, "'beanName' must not be null");
		synchronized (this.singletonObjects) {
			Object oldObject = this.singletonObjects.get(beanName);
			if (oldObject != null) {
				throw new IllegalStateException("Could not register object [" + singletonObject +
						"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
			}
			addSingleton(beanName, singletonObject);
		}
	}

	/**
	 * Add the given singleton object to the singleton cache of this factory.
	 * <p>To be called for eager registration of singletons.
	 * @param beanName the name of the bean
	 * @param singletonObject the singleton object
	 */
	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}

从上面的逻辑上可以看出,同名的类是不能被缓存进去的,会抛出异常。
好了,后的程序想getBean的时候只需要从这个缓存中获取就好了。







      

你可能感兴趣的:(spring,DI,IOC)