spring IOC源码分析(一)bean工厂的创建加载过程

本文分析了Spring的IOC功能,重点探讨了bean工厂如何创建和加载。从`ClassPathXmlApplicationContext`构造器开始,通过`refresh()`和`prepareRefresh()`方法,追踪到`obtainFreshBeanFactory()`,接着详细介绍了`refreshBeanFactory()`、`createBeanFactory()`和`loadBeanDefinitions()`的过程。在解析XML配置文件的过程中,解析bean定义并注册到`DefaultListableBeanFactory`。这是一个初步理解Spring IOC核心流程的起点。
摘要由CSDN通过智能技术生成

最近学的比较散乱,没有真正学到比较重要的东西。这几天把sprign源码再看一遍,整理下以前看的经历,同时把相关的个人心得记录下来。
spring两大功能模块,IOC和AOP,在之前已经知到了IOC原理是反射来获取bean实例,而AOP是动态代理来实现的。这里先介绍下IOC的源码,它是如何来实现的。当然目前能学到的也只是比较浅的大概流程,再复杂点的看起来就比较吃力了。
推荐在学习spring源码的时候下载一份来,好方便注释。这里先从在一开始学习时见到的说起:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(“applicationContext.xml”);
进入ClassPathXmlApplicationContext的构造器,在顺着构造器分析来到这,查看注释:


// 使用给定的父级创建新的ClassPathXmlApplicationContext,
// 从给定的XML文件加载定义。
//加载所有bean定义并创建所有单例
//或者,在进一步配置上下文后手动调用refresh。
public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {

		super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
	}

从代码可以看出这里有两个方法setConfigLocations(configLocations)和重点refresh()。显然前者是进行配置的,打开看到:

public void setConfigLocations(@Nullable String... locations) {
		if (locations != null) {
			//里面对locations进行了空值判定,如果有一个地址是空的,会抛出异常
			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;
		}
	}

于是spring相关的配置缓存在configLocations中,回到核心方法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.
			//配置bean工厂以便在此上下文中使用。
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				//允许在上下文的子类中对bean factory进行后处理
				//注册request/session scopes,一个ServletContextAwareProcessor处理器等。
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				//在上下文中调用注册为bean的工厂处理器。
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				//注册拦截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.
				//检查侦听器bean并注册它们。
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				//实例化所有剩余的(非lazy init)单例。
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				//最后一步:发布对应的事件。
				finishRefresh();
			}

在prepareRefresh()中打开可以发现这里获取了当前时间,以及进行一些设置,为接下来的刷新获取容器作准备;
然后是重点的obtainFreshBeanFactory(),获取bean工厂。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();//刷新获取DefaultListableBeanFactory类型的bean工厂,实质的配置也是在这里面配置的
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();//获取配置好的DefaultListableBeanFactory
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}

首先点开refreshBeanFactory(),它的实现类是AbstractRefreshableApplicationContext

protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();//在DisposableBean接口中,destory(),主要的销毁办法还是通过Map或set的clear()来销毁的
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();//创建工厂是默认的DefaultListableBeanFactory类型
			beanFactory.setSerializationId(getId());//设立一个id
			customizeBeanFactory(beanFactory);//对上面创建的工厂进行初始化,设置是否可以被子类重写等
			loadBeanDefinitions(beanFactory);//加载bean定义,用于读取xml配置文件
			//在解析<Bean>元素过程中没有创建和实例化Bean对象,只是创建了Bean对象的定义类BeanDefinition,
			// 将<Bean>元素中的配置信息设置到BeanDefinition中作为记录,当依赖注入时才使用这些记录信息创建和实例化具体的Bean对象。
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

首先是需要销毁之前的bean和beanFactory,对于bean实例的销毁主要是通过之前保存的map,clear()来清除。然后来到createBeanFactory(),这里创建beanFactory,是DefaultListableBeanFactory类型的,点开createBeanFactory(),发现里面是使用DefaultListableBeanFactory的构造器参数是getInternalParentBeanFactory()

protected DefaultListableBeanFactory createBeanFactory() {
		创建并返回一个DefaultListableBeanFactory工厂,其中参数是他的父工厂
		return new DefaultListableBeanFactory(getInternalParentBeanFactory());
	}

追踪getInternalParentBeanFactory()发现返回ApplicationContext,ApplicationContext是由BeanFactory派生而来的。得到ApplicationContext后便缓存在AbstractBeanFactory抽象类中,同时返回到refreshBeanFactory()中。然后看到loadBeanDefinitions(beanFactory),追踪来到它的实现类AbstractXmlApplicationContext,

@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		//方法内部是采用XmlBeanDefinitionReader来读取加载bean对象
		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.
		//允许子类提供读卡器的自定义初始化,
		// 然后继续实际加载bean定义。
		initBeanDefinitionReader(beanDefinitionReader);
		//重点
		loadBeanDefinitions(beanDefinitionReader);//通过XMLBeanDefinitionReader结合location路径信息读取Resources资源信息
	}

我们发现,这里对刚才获得的DefaultListableBeanFactory进行了xml的加载并初始化。这里进行了一些简单的配置后来到主要的加载xml的方法 loadBeanDefinitions(beanDefinitionReader),追踪源码后来到:

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isInfoEnabled()) {
			logger.info("Loading XML bean definitions from " + encodedResource);
		}

		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet<>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		try {
			//获得一个io 其实resource对象就是Spring容器中我们配置的xml文件
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				//开始准备解析xml文件了
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				//重点doLoadBeanDefinitions
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
			finally {
				inputStream.close();
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}

这里才是真正开始加载xml配置的地方,具体的解析方法实在doLoadBeanDefinitions里面。由于我们直接获取到的并不是实例bean而是BeanDefinitions ,所以当我们追踪doLoadBeanDefinitions到doRegisterBeanDefinitions方法的时候就差不多能找到它是如何解析这些xml的标签元素的

protected void doRegisterBeanDefinitions(Element root) 
		if (this.delegate.isDefaultNamespace(root)) {
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					if (logger.isInfoEnabled()) {
						logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
								"] not matching: " + getReaderContext().getResource());
					}
					return;
				}
			}
		}
		//空方法
		preProcessXml(root);
		//重点方法
		parseBeanDefinitions(root, this.delegate);
		//空方法
		postProcessXml(root);

		this.delegate = parent;
	}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		//如果使用了Spring默认的XML命名空间
		if (delegate.isDefaultNamespace(root)) {
			//遍历根元素的所有子节点
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				//如果该节点是XML元素节点
				if (node instanceof Element) {
					Element ele = (Element) node;
					//如果该节点使用的是Spring默认的XML命名空间
					if (delegate.isDefaultNamespace(ele)) {
						//使用Spring的Bean规则解析元素节点
						//重点
						parseDefaultElement(ele, delegate);
					}
					else {
						//没有使用Spring默认的XML命名空间,则使用用户自定义的解析规则解析元素节点
						//(如:自定义的xsd等)
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			//Document的根节点没有使用Spring默认的命名空间,则使用用户自定义的解析规则解析Document根节点
			delegate.parseCustomElement(root);
		}
	}
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		//如果元素节点是<Import>导入元素,进行导入解析
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		//如果元素节点是<Alias>别名元素,进行别名解析
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		//如果普通的<Bean>元素,按照Spring的Bean规则解析元素
		//bean定义解析入口
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

这里是对不同的元素进行解析,由于我们的目标是bean,于是进入processBeanDefinition

/**
	 * 处理给定的bean元素,分析bean定义
	 * 并在注册处注册。
	 * 解析bean资源
	 */
	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		//BeanDefinitionHolder是对BeanDefinition的封装,包括BeanDefinition,beanName,aliases
		//对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现
		//next
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				//向Spring IoC容器注册解析得到的Bean定义,
				//这是Bean定义向IoC容器注册的入口 ,实际上是放到一个Map里面
				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));
		}
	}

在解析过后,BeanDefinition便注册进去了。回到obtainFreshBeanFactory()还有一点要说明的是,由于DefaultListableBeanFactory是ConfigurableListableBeanFactory的实现类,所以getBeanFactory()返回的是AbstractRefreshableApplicationContext中DefaultListableBeanFactory类型的数据。
这下bean工厂基本上是获取到了,再经过一些后续处理后就可以用来获取bean了。

也许有些地方表述的不够好或者错了,还多体谅。下一节将整理关于getBean的流程分析。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值