Spring之IOC实现原理

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-bean.xml");

public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
        //设置Bean资源加载器
		super(parent);
		//设置配置路径
		setConfigLocations(configLocations);
		if (refresh) {
			//初始化容器
			refresh();
		}
	}

通过调用ClassPathXmlApplicationContext来构造一个spring的IOC容器,该构造函数主要做了三件事:

  1. 设置资源加载器和合并父类的环境变量
  2. 解析并设置配置文件的路径
  3. 初始化容器

spring使用PropertyPlaceholderHelper.replacePlaceholders来解析可能包含占位符${..}配置文件名称的

ApplicationContext bf = new ClassPathXmlApplicationContext("${prefix}-${config}.xml");

spring在读取文件,可以动态的将${..}替换成properties所配置的值,但是不能采用将配置文件引入spring的配置文件的形式

<context:property-placeholder location="classpath:spring.properties"/>

这张方式是读取不到的,因为spring读取配置文件要在读取属性文件之前,为此,要采用在系统属性里添加

Properties properties = System.getProperties();
		properties.setProperty("config", "beans");
		properties.setProperty("prefix", "spring");
		ApplicationContext bf = new ClassPathXmlApplicationContext("${prefix}-${config}.xml");

 PropertyPlaceholderHelper.replacePlaceholders又委托给parseStringValue来完成配置文件名解析,parseStringValue采用递归从内到外一层层解析占位符

protected String parseStringValue(
			String value, PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) {
    //查找${所在下标
		int startIndex = value.indexOf(this.placeholderPrefix);
		if (startIndex == -1) {
			return value;
		}

		StringBuilder result = new StringBuilder(value);
		while (startIndex != -1) {
			//查找${..}中的}位置下标
			int endIndex = findPlaceholderEndIndex(result, startIndex);
			if (endIndex != -1) {
				//提取${..}中的..子串
				String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
				String originalPlaceholder = placeholder;
				if (visitedPlaceholders == null) {
					visitedPlaceholders = new HashSet<>(4);
				}
				if (!visitedPlaceholders.add(originalPlaceholder)) {
					throw new IllegalArgumentException(
							"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
				}
				// 递归解析placeholder key.
				placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
				// 根据key=placeholder从properties中获取值
				String propVal = placeholderResolver.resolvePlaceholder(placeholder);
				if (propVal == null && this.valueSeparator != null) {
					int separatorIndex = placeholder.indexOf(this.valueSeparator);
					if (separatorIndex != -1) {
						String actualPlaceholder = placeholder.substring(0, separatorIndex);
						String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
						propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
						if (propVal == null) {
							propVal = defaultValue;
						}
					}
				}
				if (propVal != null) {
					//递归解析从properties中获取的值所包含的占位符${}
					propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
					//将${..}替换成从properties获取到的值
					result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
					if (logger.isTraceEnabled()) {
						logger.trace("Resolved placeholder '" + placeholder + "'");
					}
					startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
				}
				else if (this.ignoreUnresolvablePlaceholders) {
					// Proceed with unprocessed value.
					startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
				}
				else {
					throw new IllegalArgumentException("Could not resolve placeholder '" +
							placeholder + "'" + " in value \"" + value + "\"");
				}
				visitedPlaceholders.remove(originalPlaceholder);
			}
			else {
				startIndex = -1;
			}
		}
		return result.toString();
	}

接下来查看初始化容器

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			//准备刷新的上下文环境
			prepareRefresh();

			//初始化BeanFactory,并进行XML文件读取
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			//对BeanFactory进行各种功能填充
			prepareBeanFactory(beanFactory);

			try {
				//子类覆盖方法做额外的处理
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// 激活各种BeanFactory处理器
				invokeBeanFactoryPostProcessors(beanFactory);

				//注册拦截Bean创建的Bean处理器,这里只是注册,真正的调用是在getBean时候
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				//为上下文初始化Message源,即不同语言的消息体 ,国际化处
				initMessageSource();

				// 初始化应用消息广播器,并放入“applicationEventMulticaster”bean中
				initApplicationEventMulticaster();

				// 留给子类来初始化其它的Bean
				onRefresh();

				// 在所有注册的bean中查找Listener bean,注册到消息广播器中
				registerListeners();

				// 初始化剩下的单实例(非惰性的)
				finishBeanFactoryInitialization(beanFactory);

				// 完成刷新过程,通知生命周期处理器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;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
				contextRefresh.end();
			}
		}

(1)prepareRefresh

protected void prepareRefresh() {
		// Switch to active.
		this.startupDate = System.currentTimeMillis();
		this.closed.set(false);
		this.active.set(true);

		if (logger.isDebugEnabled()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Refreshing " + this);
			}
			else {
				logger.debug("Refreshing " + getDisplayName());
			}
		}

		// 初始化上下文环境中的任何占位符属性资源
		initPropertySources();

		//验证需要的属性文件是否都已经放入环境中
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh ApplicationListeners...
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// Reset local application listeners to pre-refresh state.
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}

		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

prepareRefresh完成的功能:

  1. 调用initPropertySources方法初始化资源配置,比如web环境下的application.properties读取
  2. 验证需要的属性文件是否都已经放入环境中
  3. earlyApplicationListenersearlyApplicationEvents早期事件 进行初始化,为的是当事件广播器applicationEventMulticaster创建好了之后,才会将早期的事件广播出去

(2) ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()

protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			//为了序列化指定id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			//初始化DodumentReader,并进行XML文件读取及解析
			loadBeanDefinitions(beanFactory);
			this.beanFactory = beanFactory;
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

obtainFreshBeanFactory主要功能:

  1. 创建DefaultListableBeanFactory
  2. 指定序列号id
  3. 对IOC容器进行定制化,设置允许循环依赖的存在等
  4. 调入载入bean定义的方法

 在初始化了DefaultListableBeanFactory和XmlBeanDefinitionReader后就可以进行配置文件的读取了

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// 创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器读取Bean定义资源
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// 配置上下文的环境,资源加载器、解析器
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// 允许子类自行初始化(比如校验机制),并提供真正的加载方法
		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}


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);
		}
	}

读取配置文件,需要首先获得资源对象Resource,spring实际调用DefaultResourceLoader.getResource来获得资源对象

public Resource getResource(String location) {
		Assert.notNull(location, "Location must not be null");

		for (ProtocolResolver protocolResolver : getProtocolResolvers()) {
			Resource resource = protocolResolver.resolve(location, this);
			if (resource != null) {
				return resource;
			}
		}

		if (location.startsWith("/")) {
			//从类路径的方式,获得资源对象
			return getResourceByPath(location);
		}
		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 (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
			}
			catch (MalformedURLException ex) {
				// No URL -> resolve as resource path.
				return getResourceByPath(location);
			}
		}
	}

接下来开始调用XmlBeanDefinitionReader.doLoadBeanDefinitions开始加载bean定义

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

		    //获得xml的文档对象
			Document doc = doLoadDocument(inputSource, resource);
            //注册bean定义
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		...
	}


public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		//使用DefaultBeanDefinitionDocumentReader实例化BeanDefinitionDocumentReader
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		//记录统计前BeanDefinition的加载个数
		int countBefore = getRegistry().getBeanDefinitionCount();
		加载及注册bean
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		//记录本次加载的BeanDefinition个数
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

在DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions开始做真正的解析工作

protected void doRegisterBeanDefinitions(Element root) {
		// Any nested <beans> elements will cause recursion in this method. In
		// order to propagate and preserve <beans> default-* attributes correctly,
		// keep track of the current (parent) delegate, which may be null. Create
		// the new (child) delegate with a reference to the parent for fallback purposes,
		// then ultimately reset this.delegate back to its original (parent) reference.
		// this behavior emulates a stack of delegates without actually necessitating one.
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

		if (this.delegate.isDefaultNamespace(root)) {
			//处理profile属性,用于区分生产环境和开发环境,
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				// We cannot use Profiles.of(...) since profile expressions are not supported
				// in XML config. See SPR-12458 for details.
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					if (logger.isDebugEnabled()) {
						logger.debug("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;
	}

处理了profile后就可以进行XML的读取了,跟踪代码进入parseBeanDefinitions(root, this.delegate)

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				if (node instanceof Element) {
					Element ele = (Element) node;
					if (delegate.isDefaultNamespace(ele)) {
						//解析默认的标签
						parseDefaultElement(ele, delegate);
					}
					else {
						//解析自定义的标签
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

        对于根节点或者子节点如果是默认命名空间的话则采用parseDefaultElement方法进行解析,否则使用delegate.parseCustomElement方法对自定义命名空间进行解析。而判断是否默认命名空间还是自定义命名空间的办法其实是使用node.getNamespaceURI()获取命名空间,并与Spring中固定的命名空间http://www.springframework.org/schema/beans进行比对。如果一致则认为是默认,否则就认为是自定义。

 跟踪解析默认标签的代码

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			//解析<import>
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			//解析<alias>
			processAliasRegistration(ele);
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			//<Bean>,则会解析并注册BeanDefinition
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

跟踪processBeanDefinition函数

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				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));
		}
	}

1. 首先委托BeanDefinitionDelegate类的parseBeanDefinitionElement方法进行元素解析,返回BeanDefinitionHolder类型的实例bdHolder,经过这个方法后,bdHolder实例已经包含我们配置文件中配置的各种属性了,例如class、name、id、alias之类的属性。
2. 当返回的bdHolder不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析。
3. 解析完成后,需要对解析后的bdHolder进行注册,同样,注册操作委托给了Bean- DefinitionReaderUtils的registerBeanDefinition方法。
4. 最后发出响应事件,通知相关的监听器,这个bean已经加载完成了

 注册bean到Map<String, BeanDefinition> beanDefinitionMap

public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		// 使用beanName作为唯一标识,注册到Map<String, BeanDefinition> beanDefinitionMap
		String beanName = definitionHolder.getBeanName();
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// 注册所有的别名
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值