基於XmlBeanFactory加載bean分析:parseCustomElement分支(三)

解析自定義標籤元素java

public BeanDefinition parseCustomElement(Element ele) {
	return this.parseCustomElement(ele, (BeanDefinition)null);
}
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
	String namespaceUri = this.getNamespaceURI(ele);
	/**
	*readerContext其實就是咱們的XmlReaderContext
	*readerContext.getNamespaceHandlerResolver()執行的具體是什麼東西呢?
	*private final NamespaceHandlerResolver namespaceHandlerResolver;就返回了這個實例變量
	* 在XmlReaderContext構造方法進行屬性初始化,咱們繼續查看XmlReaderContext初始化【分支5】
	*  這裏看到具體的DefaultNamespaceHandlerResolver
	* this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri) == DefaultNamespaceHandlerResolver.resolve(namespaceUri);
	* 這裏獲取了一個NamespaceHandler.具體這個NamespaceHandler是怎麼獲取的暫時不深究,否則進去又出不來了。
	* 可是分析下面handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));時又出現了不知所云,就是NamespaceHandler到底實現是什麼?是什麼?
	*因此不得繼續分析DefaultNamespaceHandlerResolver.resolve(namespaceUri)方法了【分支6】
	*/
	NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
	if(handler == null) {
		this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
		return null;
	} else {
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}
}
//【分支5】在XmlBeanDefinitionReader中有這麼一句代碼
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
	int countBefore = this.getRegistry().getBeanDefinitionCount();
	//this.createReaderContext(resource)建立XmlReaderContext
	documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
	return this.getRegistry().getBeanDefinitionCount() - countBefore;
}
//this.createReaderContext(resource)如何建立的呢?
public XmlReaderContext createReaderContext(Resource resource) {
	return new XmlReaderContext(resource, this.problemReporter, this.eventListener, this.sourceExtractor, this, this.getNamespaceHandlerResolver());
}
public NamespaceHandlerResolver getNamespaceHandlerResolver() {
	if(this.namespaceHandlerResolver == null) {
		this.namespaceHandlerResolver = this.createDefaultNamespaceHandlerResolver();
	}

	return this.namespaceHandlerResolver;
}
//這裏定義了NamespaceHandlerResolver最終的初始化;代碼跟蹤了半天終於找到具體須要的一個屬性的初始化啦
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
    //嘿,就是你DefaultNamespaceHandlerResolver
	return new DefaultNamespaceHandlerResolver(this.getResourceLoader().getClassLoader());
}
//【分支6】DefaultNamespaceHandlerResolver.resolve(namespaceUri)
/**
* 大概分析了這個類裏面的屬性,咱們看到這裏去加載了一個這麼META-INF/spring.handlers
* 
*/
public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver {
    public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
    protected final Log logger;
    private final ClassLoader classLoader;
    private final String handlerMappingsLocation;
    private volatile Map<String, Object> handlerMappings;

    public DefaultNamespaceHandlerResolver() {
        this((ClassLoader)null, "META-INF/spring.handlers");
    }

    public DefaultNamespaceHandlerResolver(ClassLoader classLoader) {
        this(classLoader, "META-INF/spring.handlers");
	//經過這裏咱們就能夠發現,其實幹了什麼事情?其實就是去讀取spring.handlers配置文件信息去加載一個handlerMappings
    //爲何這麼作,看看類(DefaultNamespaceHandlerResolver)默認命名空間處理器,這裏就是將咱們xml上面的標籤映射到不一樣的處理器
    //原來是這樣,通過分析咱們發現將xml中的aop標籤的處理器變成代碼中的AopNamespaceHandler	
	private Map<String, Object> getHandlerMappings() {
        if(this.handlerMappings == null) {
            synchronized(this) {
                if(this.handlerMappings == null) {
                    try {
                        Properties ex = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
                        if(this.logger.isDebugEnabled()) {
                            this.logger.debug("Loaded NamespaceHandler mappings: " + ex);
                        }

                        ConcurrentHashMap handlerMappings = new ConcurrentHashMap(ex.size());
                        CollectionUtils.mergePropertiesIntoMap(ex, handlerMappings);
                        this.handlerMappings = handlerMappings;
                    } catch (IOException var5) {
                        throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", var5);
                    }
                }
            }
        }

        return this.handlerMappings;
    }
}
---
//spring.handlers配置文件信息以下
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

【注】spring

在這塊代碼出讓我懷疑人生了?app

當new DefaultNamespaceHandlerResolver(this.getResourceLoader().getClassLoader())後咱們看到工具

DefaultNamespaceHandlerResolver這個對象中的測試

private volatile Map<String, Object> handlerMappings

竟然有屬性了?this

觀看構造方法spa

public DefaultNamespaceHandlerResolver(ClassLoader classLoader, String handlerMappingsLocation) {
    this.logger = LogFactory.getLog(this.getClass());
    Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null");
    this.classLoader = classLoader != null?classLoader:ClassUtils.getDefaultClassLoader();
    this.handlerMappingsLocation = handlerMappingsLocation;
}

其中並無設置handlerMappings屬性值?debug

那到底handlerMappings是何時初始化的呢?【我很暈】調試

通過調試咱們能夠看見handlerMappings屬性信息以下圖所屬code

裏面其實就是加載整個項目

META-INF/spring.handlers

文件其中就包含上圖所示,不少處理器。

-----到底爲何,我還要研究研究----有待補充啊

【通過一晚上思考】

一、當前項目運行環境(IDEA)

 

二、測試代碼

public class Kid {
    String name;
    double height;
    GregorianCalendar bDay;

    public Kid () {
        this.name = "HEAD";
        this.height = 1;
        this.bDay = new GregorianCalendar(1111,1,1);
    }

    public Kid (String n, double h, String date) {
        // method that toString() can't find somehow
        StringTokenizer st = new StringTokenizer(date, "/", true);
        this.name = n;
        this.height  = h;
    }

    //overriding the toString() method
    public String toString(){
        this.height = 10;
        System.out.println("toString"+this.height);
        return name+" "+height+" "+height;
    }
}

測試用例

public class Test {

    public static void main(String[] args) {
        Kid kid1 = new Kid("Lexie", 2.6, "11/5/2009");
        System.out.println(kid1);
    }
}

1、當在IDEA中配置了這個屬性時

經過調式代碼查看

height就變成10了。而在實例化這個對象的時候咱們給height賦值是2.6。

而在Kid類中咱們看到只有toString方法設置了height=10;

故而咱們能夠分析出

在勾選了全部的class都必須重寫toString()時,IDEA工具在實例化這個對象的時候就隱式調用了toString這個方法。(可是經過斷點又發現沒有執行toString方法,具體爲何會出現這樣我也不知道)

2、當未勾選時

調式結果:

也就是說這個值的變化就跟toString有關係。

進而咱們觀察spring這部分的源代碼

在DefaultNamespaceHandlerResolver類中的toString方法
//他去執行了this.getHandlerMappings()
public String toString() {
  return "NamespaceHandlerResolver using mappings " + this.getHandlerMappings();
}
//而getHandlerMappings就是完成spring.handlers的初始化
private Map<String, Object> getHandlerMappings() {
        if(this.handlerMappings == null) {
            synchronized(this) {
                if(this.handlerMappings == null) {
                    try {
                        Properties ex = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
                        if(this.logger.isDebugEnabled()) {
                            this.logger.debug("Loaded NamespaceHandler mappings: " + ex);
                        }

                        ConcurrentHashMap handlerMappings = new ConcurrentHashMap(ex.size());
                        CollectionUtils.mergePropertiesIntoMap(ex, handlerMappings);
                        this.handlerMappings = handlerMappings;
                    } catch (IOException var5) {
                        throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", var5);
                    }
                }
            }
        }

        return this.handlerMappings;
    }
//也就是說咱們爲何執行完構造方法後,發現
private volatile Map<String, Object> handlerMappings;有值了
相關文章
相關標籤/搜索