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對象。書中的例子也是到這裏就當成了一章了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章