基于XmlBeanFactory加载bean分析:parseCustomElement分支(三)

解析自定义标签元素

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

【注】

在这块代码出让我怀疑人生了?

当new DefaultNamespaceHandlerResolver(this.getResourceLoader().getClassLoader())后我们看到

DefaultNamespaceHandlerResolver这个对象中的

private volatile Map<String, Object> handlerMappings

居然有属性了?

观看构造方法

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属性值?

那到底handlerMappings是什么时候初始化的呢?【我很晕】

经过调试我们可以看见handlerMappings属性信息如下图所属

里面其实就是加载整个项目

META-INF/spring.handlers

文件其中就包含上图所示,很多处理器。

-----到底为什么,我还要研究研究----有待补充啊

【经过一夜思考】

1、当前项目运行环境(IDEA)

 

2、测试代码

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);
    }
}

一、当在IDEA中配置了这个属性时

通过调式代码查看

085246_RCqw_1243105.png

height就变成10了。而在实例化这个对象的时候我们给height赋值是2.6。

而在Kid类中我们看到只有toString方法设置了height=10;

故而我们可以分析出

在勾选了所有的class都必须重写toString()时,IDEA工具在实例化这个对象的时候就隐式调用了toString这个方法。(但是通过断点又发现没有执行toString方法,具体为什么会出现这样我也不知道)

二、当未勾选时

085607_VerK_1243105.png

调式结果:

085625_ZxNq_1243105.png

也就是说这个值的变化就跟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;有值了

 

 

 

 

 

 

 

 

 

 

转载于:https://my.oschina.net/u/1243105/blog/1489742

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值