1、Spring原始碼分析1之讀取配置檔案
阿新 • • 發佈:2019-10-09
1、XMLBeanFcatory
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactory.xml")); public class XmlBeanFactory extends DefaultListableBeanFactory { //核心程式碼,XmlBeanFactory中使用了自定義的XmlBeanDefinitionReader讀取XML檔案 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory){ //讀取XML配置檔案的核心程式碼 this.reader.loadBeanDefinitions(resource); } }
2、配置檔案封裝
載入資原始檔可以使用Spring提供的類,如
Resource resource = new ClassPathResource("beanFactory.xml");
//getInputStream是在InputStreamResource中定義的唯一方法,它也是Spring對資源封裝的最上層介面
InputStream inputStream = resource.getInputStream();
public interface InputStreamSource { InputStream getInputStream() throws IOException; } public interface Resource extends InputStreamSource { boolean exists(); boolean isReadable(); boolean isOpen(); URL getURL() throws IOException; URI getURI() throws IOException; File getFile() throws IOException; long contentLength() throws IOException; long lastModified() throws IOException; Resource createRelative(String relativePath) throws IOException; String getFilename(); String getDescription(); }
3、載入資原始檔
當使用new ClassPathResource
將資原始檔封裝為Resource
之後,就可以使用XmlBeanDefinitionReader
來讀取配置檔案。
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactory.xml")); public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory){ this.reader.loadBeanDefinitions(resource); } public int loadBeanDefinitions(Resource resource){ //EncodedResource主要用於對資原始檔的編碼處理的 return loadBeanDefinitions(new EncodedResource(resource)); } public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { //通過Set來記錄已經載入的資源,它是放在ThreadLocal中 Set<EncodedResource> currentResources = resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<EncodedResource>(4); //放入ThreadLocal中 this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException(); } try { //獲取檔案輸入流,上面已經分析過 InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } //真正進入讀取的邏輯核心部分,此處傳入的inputSource是org.xml.sax.InputResource,用於sax解析 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } } protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource){ try { //步驟1,獲取XML檔案的驗證模式,Spring用來校驗驗證模式的方法就是判斷是否包含DOCTYPE,如果包含就是DTD,否則就是XSD int validationMode = getValidationModeForResource(resource); //步驟2,載入XML檔案,並得到對應的Document Document doc = this.documentLoader.loadDocument( inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware()); //步驟3,根據返回的Document註冊Bean資訊 return registerBeanDefinitions(doc, resource); } } //步驟2 public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware){ //SAX解析XML文件,返回Document物件 DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware); DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); return builder.parse(inputSource); } //步驟3 public int registerBeanDefinitions(Document doc, Resource resource) { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); //設定環境變數 documentReader.setEnvironment(this.getEnvironment()); //記錄之前BeanDefinition中定義的Bean的數量 int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); //返回本次載入的BeanDefinition個數 return getRegistry().getBeanDefinitionCount() - countBefore; }
4、開始解析
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext){
this.readerContext = readerContext;
//讀取的根元素,debug時顯示為[beans: null]
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
//處理profile元素,profile標籤可以用於配置生產環境、開發環境等
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
Assert.state(this.environment != null, "Environment must set for evaluating profiles");
String[] specifiedProfiles
= StringUtils.tokenizeToStringArray(profileSpec,
BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
return;
}
}
//專門處理解析的代理
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(this.readerContext, root, parent);
//此處的兩個方法為空實現,面向繼承設計,這是模板方法模式,子類可以繼承並在解析前做一些處理
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
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)) {
//解析預設標籤,如bean
parseDefaultElement(ele, delegate);
}
else {
//解析自定義標籤,如<aop:aspectj-autoproxy/>
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(ro