`
zddava
  • 浏览: 243699 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Spring源代码分析 -- IOC容器(三)

阅读更多
IOC容器的基接口提供了三个获取Bean的方法:

	Object getBean(String name) throws BeansException;
	Object getBean(String name, Class requiredType) throws BeansException;
	Object getBean(String name, Object[] args) throws BeansException;


顺着XmlBeanFactory的继承结构向上找,会在AbstractBeanFactory类中找到这三个类的实现:

	public Object getBean(String name) throws BeansException {
		return getBean(name, null, null);
	}

	public Object getBean(String name, Class requiredType) throws BeansException {
		return getBean(name, requiredType, null);
	}

	public Object getBean(String name, Object[] args) throws BeansException {
		return getBean(name, null, args);
	}


这三个#getBean()方法都调用了同一个#getBean(String, Class, Object[])方法,它的实现如下:

	public Object getBean(String name, Class requiredType, Object[] args) throws BeansException {
		return doGetBean(name, requiredType, args, false);
	}


这样,处理过程就到了#doGetBean()方法了。

	protected Object doGetBean(final String name, final Class requiredType, final Object[] args,
			boolean typeCheckOnly) throws BeansException {

		// 处理"&"前缀和别名
		final String beanName = transformedBeanName(name);
		Object bean = null;

		// 获得原始的单例对象
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {// 如果已经创建了这个实例
			if (logger.isDebugEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
				} else {
					logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			// 对sharedInstance进行一些判断(如FactoryBean等),来获得最终的Bean实例
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		} else {// 如果还没有创建
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// 检查在父BeanFactory中有没有这个Bean的定义
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				String nameToLookup = originalBeanName(name);
				if (args != null) {
					return parentBeanFactory.getBean(nameToLookup, args);
				} else {
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
			}

			if (!typeCheckOnly) {
				// 标记Bean已经创建,其实是在一个名字是alreadyCreated的Set里加入beanName
				markBeanAsCreated(beanName);
			}

			// 返回BeanDefinition,里边包括了xml中定义的bean的信息
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);

			// 检查Bean的dependsOn,如果有的话就要先实例化它所依赖的Bean
			String[] dependsOn = mbd.getDependsOn();
			if (dependsOn != null) {
				for (int i = 0; i < dependsOn.length; i++) {
					String dependsOnBean = dependsOn[i];
					getBean(dependsOnBean);
					registerDependentBean(dependsOnBean, beanName);
				}
			}

			if (mbd.isSingleton()) {
				// 如果Bean是单例的,创建一个单例
				sharedInstance = getSingleton(beanName, new ObjectFactory() {
					public Object getObject() throws BeansException {
						try {
							return createBean(beanName, mbd, args);
						} catch (BeansException ex) {
							// 销毁单例
							destroySingleton(beanName);
							throw ex;
						}
					}
				});
				// 根据单例生成Bean实例
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			} else if (mbd.isPrototype()) {
				// 创建prototype的实例,每次都创建一个新的实例
				Object prototypeInstance = null;
				try {
					beforePrototypeCreation(beanName);
					prototypeInstance = createBean(beanName, mbd, args);
				} finally {
					afterPrototypeCreation(beanName);
				}
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			} else {
				// 得到scope,为RequestScope,SessionScope中的一个
				String scopeName = mbd.getScope();
				final Scope scope = (Scope) this.scopes.get(scopeName);
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
				}
				try {
					Object scopedInstance = scope.get(beanName, new ObjectFactory() {
						public Object getObject() throws BeansException {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							} finally {
								afterPrototypeCreation(beanName);
							}
						}
					});
					bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
				} catch (IllegalStateException ex) {
					throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; " + "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex);
				}
			}
		}

		// 检查Bean的类是否正确
		if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
			throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
		}
		return bean;
	}


这个方法的实现包括了几个需要进一步查看的点。首先,是单例对象的获取,就是#getSingleton(String)这个方法

	public Object getSingleton(String beanName) {
		return getSingleton(beanName, true);
	}

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 从已经创建的单例对象map中获取实例
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null) {
			synchronized (this.singletonObjects) {
				// 从已经创建的early单例对象map中获取实例
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					// 获得单例工厂
					ObjectFactory singletonFactory = (ObjectFactory) this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						// 在earlySingletonObjects这个Map中"注册"上这个Bean,下次相同的Bean就可以直接获取了
						this.earlySingletonObjects.put(beanName, singletonObject);
						// 在singletonFactories移除相关的记录
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}


这个方法中涉及到了3个Map,singletonObjects,earlySingletonObjects和singletonFactories。另外还有一个ObjectFactory的实例用来生成单例,接下来的介绍中还会出现这些对象的,先做一个提醒。

回到#doGetBean()方法,在通过#getSingleton(String)方法获得了单例后,程序出现了两个分支,其中之一是sharedInstance不为null,就是说之前的操作中已经实例化了一个与此beanName相关的实例,另外还要当args为null(args不为null一定是prototype的Bean)时,那么就可以准备获取最终的Bean实例了,具体是通过这个getObjectForBeanInstance(Object, String, String, RootBeanDefinition)方法,它的源代码如下:

	protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName,
			RootBeanDefinition mbd) {

		// 如果name以"&"开头,并且beanInstance不是FactoryBean的情况下,抛出异常
		if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
		}

		// 分两种情况
		// 1. beanInstance不是FactoryBean,name不是以"&"开头,此时返回bean
		// 2. beanInstance是FactoryBean,name是以"&"开头,此时返回FactoryBean
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

		// 最后一种情况是name不是以"&"开头,并且beanInstance是FactoryBean的情况
		// 此时要调用FactoryBean来构造一个Bean了
		Object object = null;
		if (mbd == null) {
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			FactoryBean factory = (FactoryBean) beanInstance;
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			// 调用FactoryBean的#getObject()来构建bean
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}


执行完这个方法后就可以返回Bean的实例给客户端了。

好,再次回到#doGetBean()方法,进入到另外一个分支,就是IOC容器之前还没有实例化sharedInstance的情况,这是就要新建一个了。在具体的Bean实例生成过程中,按照Scope出现了3个不同的实现方式,分别为singleton,prototype以及request和session。

对于scope为singleton的情况,首先获取一个bean的单例,然后根据单例来获取最终的Bean实例。

	sharedInstance = getSingleton(beanName, new ObjectFactory() {
		public Object getObject() throws BeansException {
			try {
				return createBean(beanName, mbd, args);
			} catch (BeansException ex) {
				// 销毁单例
				destroySingleton(beanName);
				throw ex;
			}
		}
	});
	// 根据单例生成Bean实例
	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);


这里的bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);这句方法调用之前已经讲过了,需要重点了解的是那个单例的获取。

	public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
		Assert.notNull(beanName, "'beanName' must not be null");
		synchronized (this.singletonObjects) {
			// 尝试直接获取
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while the singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
				beforeSingletonCreation(beanName);
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet();
				}
				try {
					// 通过ObjectFactory来获取实例
					singletonObject = singletonFactory.getObject();
				} catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Iterator it = this.suppressedExceptions.iterator(); it.hasNext();) {
							ex.addRelatedCause((Exception) it.next());
						}
					}
					throw ex;
				} finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					afterSingletonCreation(beanName);
				}
				//向singletonObjects这个Map注册刚生成的实例,下次可以直接从Map中获取
				addSingleton(beanName, singletonObject);
			}
			return (singletonObject != NULL_OBJECT ? singletonObject : null);
		}
	}


这个方法的重点是知道了Bean单例的创建过程是通过ObjectFactory的#getObject()方法来完成的,另外,在方法的最后会向Map中注册新成生的实例。与#doGetBean()方法前面的处理过程形成呼应了。

下面还是来看看这个#getObject()方法,这个是通过匿名类来实现的:

	sharedInstance = getSingleton(beanName, new ObjectFactory() {
		public Object getObject() throws BeansException {
			try {
				return createBean(beanName, mbd, args);
			} catch (BeansException ex) {
				// 销毁单例
				destroySingleton(beanName);
				throw ex;
			}
		}
	});


在#getObject()内调用了#createBean()方法,而这个方法在AbstractBeanFactory中是abstract的,需要子类去实现,我们可以来看看子类是怎么实现的。

在XmlFactoryBean的一个父类,并且是AbstractBeanFactory的一个子类AbstractAutowireCapableBeanFactory中就有一个这样的定义:

	protected Object createBean(final String beanName, final RootBeanDefinition mbd,
			final Object[] args) throws BeanCreationException {

		AccessControlContext acc = AccessController.getContext();
		return AccessController.doPrivileged(new PrivilegedAction() {
			public Object run() {
				if (logger.isDebugEnabled()) {
					logger.debug("Creating instance of bean '" + beanName + "'");
				}
				resolveBeanClass(mbd, beanName);

				try {
					// 方法重写功能
					mbd.prepareMethodOverrides();
				} catch (BeanDefinitionValidationException ex) {
					throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
							"Validation of method overrides failed", ex);
				}

				try {
					// 创建一个Bean的proxy
					Object bean = resolveBeforeInstantiation(beanName, mbd);
					if (bean != null) {
						return bean;
					}
				} catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"BeanPostProcessor before instantiation of bean failed", ex);
				}
				// 创建一个Bean的实例
				Object beanInstance = doCreateBean(beanName, mbd, args);
				if (logger.isDebugEnabled()) {
					logger.debug("Finished creating instance of bean '" + beanName + "'");
				}
				return beanInstance;
			}
		}, acc);
	}


这里,#resolveBeforeInstantiation()是用于处理继承了InstantiationAwareBeanPostProcessor接口的类的回调,重要的是#doCreateBean()方法,但是此方法的流程比较长,下一节接着说。
分享到:
评论

相关推荐

    Spring.net二----初探IOC容器.rar源代码

    Spring.Demo项目很可能是包含一个简单的Spring.NET应用示例,可能包括了XML配置文件、服务接口和实现类、以及如何使用IoC容器来获取和使用这些对象的代码。通过这个示例,你可以更直观地了解如何在实际项目中运用...

    Spring源代码解析(一):IOC容器.doc

    在Spring源代码解析的第一部分,我们将聚焦于IOC容器,特别是BeanFactory接口,它是所有Spring容器的基础。 BeanFactory接口是Spring的基石,它定义了基本的容器操作,如获取Bean、检查Bean是否存在、确定Bean的...

    spring-demo10-注解-IOC.zip

    注解是Java语言提供的一种元数据机制,允许我们在源代码中嵌入信息,这些信息可以被编译器或者运行时环境解析和使用。Spring框架充分利用了这一特性,提供了一系列注解来简化配置,使得我们可以避免使用XML配置文件...

    Spring源代码解析

    Spring源代码解析(一):IOC容器 Spring源代码解析(二):IoC容器在Web容器中的启动 Spring源代码解析(三):Spring JDBC Spring源代码解析(四):Spring MVC Spring源代码解析(五):Spring AOP获取Proxy Spring源...

    Spring源代码解析.rar

    Spring源代码解析1:IOC容器.doc Spring源代码解析2:IoC容器在Web容器中的启动.doc Spring源代码解析3:Spring JDBC .doc Spring源代码解析4:Spring MVC .doc Spring源代码解析5:Spring AOP获取Proxy .doc Spring...

    Spring2.5.6源代码分析(一):IOC容器

    IoC容器是Spring框架的心脏,它负责管理对象的生命周期和依赖关系,使得开发者能够实现松耦合和高可测试性的应用程序。 首先,我们来理解什么是IoC。IoC,也被称为依赖注入(Dependency Injection),是一种设计...

    Spring 源代码解析

    Spring源代码解析1:IOC容器;Spring源代码解析2:IoC容器在Web容器中的启动;Spring源代码解析3:Spring JDBC ; Spring源代码解析4:Spring MVC ;Spring源代码解析5:Spring AOP获取Proxy;Spring源代码解析6:...

    Spring源代码解析(二):IoC容器在Web容器中的启动.doc

    当我们在Web环境中运行Spring应用时,IoC容器需要在Web容器(如Tomcat、Jetty等)中启动并运行。这个过程涉及到一系列的初始化步骤,确保Spring能够正确地与Web容器集成。 首先,`WebApplicationContext`是`...

    Spring-IoC 容器 - v1.01

    Spring支持多种持久化技术,如JDBC、Hibernate、MyBatis等,可以利用IoC容器管理这些DAO对象,使它们能够依赖于事务管理、数据源等服务。 **工厂模式** 工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳...

    spring ioc容器部署实现

    ### Spring IoC容器部署实现详解 #### 一、Spring IoC容器概述 Spring框架的核心特性之一就是Inversion of Control(IoC),也被称为Dependency Injection(DI)。IoC容器是Spring框架的重要组成部分,它负责管理...

    springIOC核心组件分析.vsdx

    spring-context:上下文,即IOC容器 spring-context-support:对IOC的扩展,以及IOC子容器 spring-context-indexer:类管理组件和Classpath扫描 spring-expression:表达式语句 切面编程: spring-aop:面向切面编程,...

    spring-framework-2.5-rc2-with-dependencies\spring-framework-2.5-rc2\spring-framework-2.5-rc2源代码

    通过阅读和学习这些源码,开发者可以了解到Spring如何实现IoC容器、AOP代理、事件机制、任务调度等多个关键功能。同时,这也有助于开发者更好地理解和使用Spring提供的API,以及在实际项目中如何定制和扩展Spring。 ...

    SpringIOC示例源代码

    3. `TestIoC.java`:这是一个关于IoC容器的测试类,它可能使用Spring的ApplicationContext接口来加载bean.xml配置,然后通过容器获取并测试bean实例。 4. `ServiceBean.java`:这可能是一个通用的服务bean,用于...

    spring-webmvc-struts.jar

    例如,`StrutsActionProxy`类是如何拦截Struts的请求,然后通过Spring的IoC容器查找并调用对应的bean方法。同时,源代码中还展示了如何将Struts的配置信息与Spring的bean定义相结合,实现配置的统一管理和重用。 ...

    spring-context-3.2.0 spring-core-3.2.0 等齐全的Spring jar包

    这里提到的是一组完整的Spring库,包括`spring-core`、`spring-context`、`spring-webmvc`、`spring-web`、`spring-beans`、`spring-test`、`spring-jdbc`、`spring-orm`、`spring-aop`和`spring-tx`,它们都是3.2.0...

    spring源代码解析

    2. **Web环境下的IOC容器启动**:"spring源代码解析(二):IOC容器在web中启动.doc"涵盖了在Web应用中初始化Spring容器的过程,包括ApplicationContext的创建、DispatcherServlet的配置以及如何在Web环境中注入bean...

    spring核心技术源代码spring核心技术源代码1-9章

    通过阅读并分析这些源代码,开发者可以更深入地理解Spring框架的工作机制,学习如何有效地使用其特性来提高代码的可维护性和可扩展性。每个章节都会提供实际的示例,帮助开发者将理论知识转化为实践技能。对于想要...

    Spring IoC简单示例-注解配置-Maven构建

    Spring IoC容器通过解析XML配置文件或使用注解来识别对象及其依赖关系,并在运行时自动装配这些对象,这就是依赖注入。 在Spring中,注解配置是取代传统XML配置的一种方式,它使得代码更加简洁、易读。例如,我们...

Global site tag (gtag.js) - Google Analytics