第五讲的代码块4:registerBeanDefinitions(doc, resource)的内部代码块2的最后已经提到了BeanDefinitionParserDelegate才是真正用于解析BeanDefinition的,下面我们来详解下这个类
1、简述这个类的作用:
这个类是真正解析BeanDefiniton的类(它是一个被委托的类):
属性:它里面的属性定义了要解析的xml文件中出现的所有名字,如:
元素名、属性名等。如:String NAME_ATTRIBUTE = "name";String BEAN_ELEMENT = "bean";String ID_ATTRIBUTE = "id";String CLASS_ATTRIBUTE = "class";等
方法:当然它里面还定义了一系列操作BeanDefinition的方法:如:
parseBeanDefinitionElement()方法解析出BeanDefinition
因为只有把这些信息都注册到这个类中,这个类才能使用这些属性,很方便的解析BeanDefinition嘛。
2、该类中用到了两个设计模式:
委托设计模式,委托类负责执行真正的操作之前的一系列准备操作,真正的操作是交给被委托类处理的
模板方法模式:
1、createHelper
2、populateDefaults
3、DocumentDefaultDefinition
registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
/**
* This implementation parses bean definitions according to the "spring-beans" XSD
* (or DTD, historically).
* <p>Opens a DOM Document; then initializes the default settings
* specified at the {@code <beans/>} level; then parses the contained bean definitions.
*/
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
//设置ReaderContext(具体作用不详)
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
//得到Document中的根元素,也就是<beans>标签,因为只要获取到了根元素,就能通过根元素获取到其他任何子元素和属性。这点和js中的document对象类型
Element root = doc.getDocumentElement();
//真正注册BeanDefinition的方法(详解见:代码块1)
doRegisterBeanDefinitions(root);
}
代码块1:doRegisterBeanDefinitions(root)
/**
* Register each bean definition within the given root {@code <beans/>} element.
*/
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
//任何嵌套的<beans>元素都会在这个方法中引起递归。在
//为了正确地传播和保存<beans> default-*属性,
//跟踪当前(父)委托,可能为空。创建
//新的(子)委托,它有一个对父类的引用,
//然后最终将this.delegate重置为其原始(父)引用。
//这个行为模拟了一堆委托,但实际上并不需要一个。
//也就是说这里会出现递归调用的可能(具体是这个方法会递归调用,还是这个方法里面有递归调用暂时不清楚)
//看上面的翻译,当存在一个<beans>中嵌套<beans>时会导致递归。为什么会出现<beans>中包含<beans>的情况呢?因为spring配置文件支持:一个配置文件引入另一个配置文件。
//先将当前的BeanDefinitionParserDelegate保存到一个新的变量,parent代表子<beans>的父<beans>
BeanDefinitionParserDelegate parent = this.delegate;
//创建新的BeanDefinitionParserDelegate (详解见:内部代码块1)
this.delegate = createDelegate(getReaderContext(), root, parent);
//一些意义不大的操作
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
//这里用到了模板方法的设计模式
//是spring框架设计出的一个扩展点,默认preProcessXml()和postProcessXml()只提供空方法,具体实现又开发人员根据自己业务的需求自己在子类中重写此方法
//一般这两个方法的作用是:当我们在xml自定义元素时(不是spring里面规定的元素,而是可能为了实现某种功能,我们自己编写的元素,spring框架本身不能解析识别),才需要重写这两个方法
preProcessXml(root);
//该方法开始真正解析BeanDefinition(详解见:第8讲)
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
内部代码块1:
protected BeanDefinitionParserDelegate createDelegate(
XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
//创建一个BeanDefinitionParserDelegate
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
//执行初始化操作,就是设置一个默认值 (详情见:内部代码块2)
delegate.initDefaults(root, parentDelegate);
return delegate;
}
内部代码块2:
/**
* Initialize the default lazy-init, autowire, dependency check settings,
* init-method, destroy-method and merge settings. Support nested 'beans'
* element use cases by falling back to the given parent in case the
* defaults are not explicitly set locally.
* @see #populateDefaults(DocumentDefaultsDefinition, DocumentDefaultsDefinition, org.w3c.dom.Element)
* @see #getDefaults()
*/
public void initDefaults(Element root, BeanDefinitionParserDelegate parent) {
//(详情见:内部代码块3)
populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
//触发一个默认注册事件。
this.readerContext.fireDefaultsRegistered(this.defaults);
}
内部代码块3:
/**
* Populate the given DocumentDefaultsDefinition instance with the default lazy-init,
* autowire, dependency check settings, init-method, destroy-method and merge settings.
* Support nested 'beans' element use cases by falling back to <literal>parentDefaults</literal>
* in case the defaults are not explicitly set locally.
* @param defaults the defaults to populate
* @param parentDefaults the parent BeanDefinitionParserDelegate (if any) defaults to fall back to
* @param root the root element of the current bean definition document (or nested beans element)
*/
//这个方法就是把root中的属性设置到新创建的DocumentDefaultsDefinition 中
protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) {
String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE);
if (DEFAULT_VALUE.equals(lazyInit)) {
// Potentially inherited from outer <beans> sections, otherwise falling back to false.
lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE);
}
defaults.setLazyInit(lazyInit);
String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE);
if (DEFAULT_VALUE.equals(merge)) {
// Potentially inherited from outer <beans> sections, otherwise falling back to false.
merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE);
}
defaults.setMerge(merge);
String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE);
if (DEFAULT_VALUE.equals(autowire)) {
// Potentially inherited from outer <beans> sections, otherwise falling back to 'no'.
autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE);
}
defaults.setAutowire(autowire);
// Don't fall back to parentDefaults for dependency-check as it's no longer supported in
// <beans> as of 3.0. Therefore, no nested <beans> would ever need to fall back to it.
defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));
if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {
defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
}
else if (parentDefaults != null) {
defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates());
}
if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
}
else if (parentDefaults != null) {
defaults.setInitMethod(parentDefaults.getInitMethod());
}
if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
}
else if (parentDefaults != null) {
defaults.setDestroyMethod(parentDefaults.getDestroyMethod());
}
defaults.setSource(this.readerContext.extractSource(root));
}