spring源码学习(三)容器的基本实现

看spring源码深度解析,记录一下第二章容器的基本实现。

启动spring

启动spring的main方法

public static void main(String[] args) {
//首先自己定义一个bean.xml文件,里面定义一个简单的bean标签就行。
		Resource resource = new ClassPathResource("bean.xml");
		//实例化一个beanfactory工厂,用来处理bean的一些实例化的东西,实际开发很少这样用。
		BeanFactory factory = new DefaultListableBeanFactory();
		//XmlBeanDefinitionReader是用来解析bean.xml文件的,把xml解析成elemet之后当成参数放到BeanFactory工厂进行解析,
		BeanDefinitionReader bdr = new XmlBeanDefinitionReader((BeanDefinitionRegistry) factory);
		//调用加载bean的方法了,这开始真真的把xml里面定义的属性编程一个一个的java对象了。
		//看过程就说从这里开始看起。
		bdr.loadBeanDefinitions(resource);
		Student student = factory.getBean("stu", Student.class);
		System.out.printf("。。。。。。" + student);
	}

bdr.loadBeanDefinitions(resource);
这行代码开始加载,点进去就进到XmlBeanDefinitionReaderloadBeanDefinitions方法
loadBeanDefinitions方法就是这样的。

	@Override
	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
	//这个loadBeanDefinitions方法又调用重载方法loadBeanDefinitions,传入的参数是EncodedResource
		return loadBeanDefinitions(new EncodedResource(resource));
	}

loadBeanDefinitions(EncodedResource encodedResource) 这个方法的代码说这样的

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("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 {
		//转换成inpustStream,这个就是我们常用的输入流了,xml转换成流之后就能转换成element元素了。
			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异常的代码
	}

return doLoadBeanDefinitions(inputSource, encodedResource.getResource());的方法代码如下

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

		try {
		//这里把InputSource转换成了Document,看到这个就想起我们熟悉的xml了吧,哈哈。
			Document doc = doLoadDocument(inputSource, resource);
			//调用下面这个方法之后就完成了bean的注册了,bean的注册是spring的核心。
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
		.........省略那些catch异常的代码。
	}

int count = registerBeanDefinitions(doc, resource);的代码是这样的

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//实例化BeanDefinitionDocumentReader,这个就是定义bean的对象,解析bean的各种标签,这里默认的实现是DefaultBeanDefinitionDocumentReader这个类,这里是调用createBeanDefinitionDocumentReader()方法通过反射完成实例化的。
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		//获取当前定义的bean的个数,第一次进来这里肯定说0.
		int countBefore = getRegistry().getBeanDefinitionCount();
		//这里就开始进入解析bean标签的方法了。
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		//两个数字相减得到当前定义了多少个bean了。
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

documentReader.registerBeanDefinitions(doc, createReaderContext(resource));方法点进去,一步一步点下去就掉用到doRegisterBeanDefinitions(Element root)这个方法

protected void doRegisterBeanDefinitions(Element root) {
//下面这两个应该是spring的父子容器,暂时还没看明白是啥意思。
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);
//判断是不是使用的spring的默认标签
		if (this.delegate.isDefaultNamespace(root)) {
		//解析profile标签,profile标签就是我们平时用来定义spring的多给环境的。
		//这里逻辑判断比较简单,就是进行验证一下。
			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);
		//解析bean标签了
		parseBeanDefinitions(root, this.delegate);
		//这个方法是空的,方便继续此类的人进行二次开发。
		postProcessXml(root);
		this.delegate = parent;
	}

parseBeanDefinitions(root, this.delegate);方法的代码如下

/**
	 * Parse the elements at the root level in the document:
	 * "import", "alias", "bean".
	 * @param root the DOM root element of the document
	 */
	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)) {
					//解析以及注册BeanDefinitions对象
						parseDefaultElement(ele, delegate);
					}
					else {
						//解析自定义标签,spring支持自定义标签,用来实现自己的业务,比如说dubbo的标签,apollo的标签哈。
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
		//解析自定义标签,spring支持自定义标签,用来实现自己的业务,比如说dubbo的标签,apollo的标签哈。
			delegate.parseCustomElement(root);
		}
	}

spring的自定义标签的定义和解析网上有很多的例子。
到这里为止spring读取xml文件转换成Element就完成了,接下来就是把Element转换spring的bean对象。书中的例子也是到这里就当成了一章了。

上一篇:C#委托,匿名方法,Lambda,泛型委托,表达式树代码示例


下一篇:.NET 中易混淆的概念三 (Delegate vs Event)