上一节我们分析了配置文件的加载,我们已经了解到了spring是如何加载配置文件的。那么这一节我们开始了解一下spring是如何解析这些资源的。

public int XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isInfoEnabled()) {
			logger.info("Loading XML bean definitions from " + encodedResource.getResource());
		}
        
        //从当前线程中获取资源,这里的EncodedResource是对其他Resource的一种装饰,主要用于资源的编码。
		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet<EncodedResource>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		//如果当前资源已经配置过了,那么不允许重复配置。
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		try {
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				//加载资源
				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();
			}
		}
	}
	
	//XmlBeanDefinitionReader关联了一个实现了DocumentLoader的类,通过w3c,jdk自带的一个xml解析器去解析xml,在解析前会判断xml的校验模式,spring是通过xml中是否存在DOCTYPE这个标识去判断的
	public Document org.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(InputSource inputSource, EntityResolver entityResolver,
			ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
        //构建DocumentBuilderFactory
		DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
		if (logger.isDebugEnabled()) {
			logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
		}
		DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
		//返回Document
		return builder.parse(inputSource);
	}
	

    spring通过w3c创建了Document。


public int org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        //创建BeanDefinition文档阅读器
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

    到这里又创建了一个BeanDefinitionDocumentReader实例,spring各个类的关联关系变得越来越复杂,如果不做些记录的话,我们可能要迷失在代码的海洋里了,何况此时只是spring的冰山一角。那么解析来我们先看下BeanDefinitionDocumentReader的类图

在这里插入图片描述

这里主要提一下,在AbstractBeanDefinitionReader中关联的BeanDefinitionRegistry实际上是DefaultListableBeanFactory,这个类实现了BeanDefinitionRegistry接口,ResourceLoader实际引用的是我们分析的XmlWedApplicationContext, Environment实际是我们分析的StandardServletEnvironment

protected void doRegisterBeanDefinitions(Element root) {
		//spring的解析配置文件的工作实际使用的是BeanDefinitionParserDelegate,这里类从类图上看还关联了DocumentDefaultsDefinition,这个类是用来存储beans元素上的一些默认配置,比如default-lazy-init,default-autowire
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);
        
        //判断当前元素是否spring默认命名空间的内容,如果是,就获取上面的profile元素,这个元素是用来指定默认的激活的配置
		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)) {
					return;
				}
			}
		}
        
        //钩子函数,内部没有任何实现,子类可以覆盖它,进行一些逻辑的处理,解析BeanDefinition的前置处理
		preProcessXml(root);
		parseBeanDefinitions(root, this.delegate);
		//钩子函数,空方法,解析完当前配置的后置处理
		postProcessXml(root);

		this.delegate = parent;
	}

    现在我们创建了BeanDefinition解析的委托类,并且解析了根元素的默认配置,那么接下来就开始具体元素的解析

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        //spring默认命名空间的元素走默认解析方式,不是默认空间的走自定义解析方式,默认空间的元素spring是知道怎么解析的,但是像我们自己定义的那些自定义元素,spring是不知道怎么解析的。
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				//只处理元素类型的标签,想text类型的不处理
				if (node instanceof Element) {
					Element ele = (Element) node;
					//如果是默认命名空间元素,使用默认解析方式
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					//如果是嵌入的自定义元素,走自定义元素解析方式
					else {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		//如果是自定义元素,走自定义元素解析方式
		else {
			delegate.parseCustomElement(root);
		}
	}

    我们先来看看spring是如何解析自定义元素标签的

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        //获取命名空间uri
		String namespaceUri = getNamespaceURI(ele);
		//通过命名空间uri解析出对应标签的处理器,命名空间处理器会加载当前加载器及其父加载器类路径下所有META-INF/spring.handlers
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		//处理自定义标签
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

    可以看到,spring要解析自定义标签,必须从META-INF/spring.handlers找到对应的命名空间处理器,如果找不到将不会没法解析当前命名空间下的标签,为了了解自定命名空间是怎么工作的,那么我们在spring众多实现里挑选一个AopNamespaceHandler来解析一下

在这里插入图片描述

  1. NamespaceHandler(定义初始化标签解析器,定义获取BeanDefinition以及装饰BeanDefinition的能力)

  2. NamespaceHandlerSupport(提供查找具体标签解析器的能力,用户只需继承它,实现init方法,与具体的标签解析器就可以了)

    下面就是AopNamespaceHandler的init方法实现

public void init() {
		// In 2.0 XSD as well as in 2.1 XSD.
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

		// Only in 2.0 XSD: moved to context namespace as of 2.1
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
	}

    以上定义了各个标签的解析器和装饰器,他们分别实现了BeanDefinitionParser和BeanDefinitionDecorator接口,BeanDefinitionParser用于将元素解析成BeanDefinition,而BeanDefinitionDecorator会在原来的BeanDefinition上进行装饰,假设我们在配置文件中配置了这样一个标签,那么最后解析这个标签的解析器是上面定义的AspectJAutoProxyBeanDefinitionParser解析器,下面是这个解析器的parse方法

public BeanDefinition parse(Element element, ParserContext parserContext) {
        //注册AspectJAnnotationAutoProxyCreator
		AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
		//设置includePatterns,用于过滤bean
		extendBeanDefinition(element, parserContext);
		return null;
	}

    上面这段代码中有两个参数,第一个参数是要解析的标签元素,第二个参数是以个解析上下文,为了弄清楚里面关联了什么,我们来画个类图

在这里插入图片描述

这个ParseContext关联了XmlReaderContext和BeanDefinitionParserDelegate,结合BeanDefinitionDocumentReader的类图,应该很好理解

    了解了parse方法的参数,那么我们继续看看AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary这个方法到底做了什么

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			ParserContext parserContext, Element sourceElement) {
        //创建AspectJAnnotationAutoProxyCreator的BeanDefinition
		BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
				parserContext.getRegistry(), parserContext.extractSource(sourceElement));
		//设置是否强制使用cglib代码,设置是否暴露代理对象
		useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
		registerComponentIfNecessary(beanDefinition, parserContext);
	}

    上面一段代码只是将逻辑都封装成了单独的方法去处理


public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}

//AnnotationAwareAspectJAutoProxyCreator.class
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		//判断BeanFactory中是否已经存在了这个BeanDefinition
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
		    //如果已经存在了,那么判断是否是同一个,如果不是,那么就判断他们的优先级,优先级高的会替换优先级低的
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
				int requiredPriority = findPriorityForClass(cls);
				if (currentPriority < requiredPriority) {
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			return null;
		}
		//创建BeanDefinition
		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		//设置属性order的值
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		//设置BeanDefinition的角色,ROLE_INFRASTRUCTURE角色的bean不会被后置处理器处理,这个在分析bean创建的章节会提到
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		//注册这个BeanDefinition到BeanFactory中
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}
	
	//设置是否强制使用cglib代理,设置是否暴露代理对象
	private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
		if (sourceElement != null) {
		    //解析proxy-target-proxy
			boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
			if (proxyTargetClass) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			//解析expose-proxy-attribute
			boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
			if (exposeProxy) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}
	

    上面这段代码创建了注解aop后置处理器的BeanDefinition,并给它设置了元素标签指定的属性,后置处理器是spring给予用户参与创建bean过程的一种扩展方式,我们现在创建的这个后置处理器,将会参与aop注解增强的过程。自定义标签的解析就到这里,下面本节的序列图

在这里插入图片描述

严格来说,前面创建Document的过程是解析默认标签与解析自定义标签共同的流程,后面部分才是解析自定标签的过程,基于此,我们自己也可以实现自己的标签