最近在看Spring源代码,对配置文件信息的载入是使用Spring的第一步 ,而这第一步就是一个非常复杂的过程....
Spring通过定义BeanDefination来管理Ioc中的各种对象以及它们之间的依赖关系,所以载入的过程其实就是将XML文件读取并解析成BeanDefination数据的过程。
我们以最常使用的ClassPathXmlApplicationContext为切入点
1. 创建一个ClassPathXmlApplicationContext对象,传入文件路径
Java代码
- ClassPathXmlApplicationContext re = new ClassPathXmlApplicationContext("applicationContext.xml");
ClassPathXmlApplicationContext re = new ClassPathXmlApplicationContext("applicationContext.xml");
这个构造方法会重载到
- public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
- throws BeansException {
- super(parent);
- setConfigLocations(configLocations);
- if (refresh) {
- refresh();
- }
- }
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
其中首先设置配置路径 setConfigLocations(configLocations) ,而后进行刷新 refresh(), 而这个refresh()方法是Ioc容器初始化的入口
2.refresh方法的结构
refresh方法由AbstractApplicationContext实现
- public void refresh() throws BeansException, IllegalStateException {
- synchronized (this.startupShutdownMonitor) {
- // Prepare this context for refreshing.
- prepareRefresh();
- // Tell the subclass to refresh the internal bean factory.
- ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
- // Prepare the bean factory for use in this context.
- prepareBeanFactory(beanFactory);
- try {
- // Allows post-processing of the bean factory in context subclasses.
- postProcessBeanFactory(beanFactory);
- // Invoke factory processors registered as beans in the context.
- invokeBeanFactoryPostProcessors(beanFactory);
- // Register bean processors that intercept bean creation.
- registerBeanPostProcessors(beanFactory);
- // Initialize message source for this context.
- initMessageSource();
- // Initialize event multicaster for this context.
- initApplicationEventMulticaster();
- // Initialize other special beans in specific context subclasses.
- onRefresh();
- // Check for listener beans and register them.
- registerListeners();
- // Instantiate all remaining (non-lazy-init) singletons.
- finishBeanFactoryInitialization(beanFactory);
- // Last step: publish corresponding event.
- finishRefresh();
- }
- catch (BeansException ex) {
- // Destroy already created singletons to avoid dangling resources.
- destroyBeans();
- // Reset 'active' flag.
- cancelRefresh(ex);
- // Propagate exception to caller.
- throw ex;
- }
- }
- }
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
这个方法中描述了ApplicationContext的整个初始化过程,包括BeanFactory的更新,还有messagesource以及一些生命周期有关属性的注册,而我们关心的是BeanFactory的更新,即obtainFreshBeanFactory()方法
3.启动对BeanDefination的载入
还是在ApplicationContext类中
- protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
- refreshBeanFactory();
- ConfigurableListableBeanFactory beanFactory = getBeanFactory();
- if (logger.isDebugEnabled()) {
- logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
- }
- return beanFactory;
- }
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
它的第一步交给一个抽象方法refreshBeanFactory(), 具体的实现在AbstractRefreshableApplicationContext类中
- @Override
- protected final void refreshBeanFactory() throws BeansException {
- if (hasBeanFactory()) {
- destroyBeans();
- closeBeanFactory();
- }
- try {
- DefaultListableBeanFactory beanFactory = createBeanFactory();
- beanFactory.setSerializationId(getId());
- customizeBeanFactory(beanFactory);
- loadBeanDefinitions(beanFactory);
- synchronized (this.beanFactoryMonitor) {
- this.beanFactory = beanFactory;
- }
- }
- catch (IOException ex) {
- throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
- }
- }
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
第一步是判断是否已经创建过BeanFactory,如果是,将它销毁,重新创建
第二步就是创建各种ApplicationContext持有的真正容器实现类DefaultListableBeanFactory,创建Ioc容器
最后启动BeanDefination的载入 loadBeanDefinitions(beanFactory)方法
4.BeanFactory将载入工作交给BeanDefinationReader
loadBeanDefinitions(beanFactory)方法是抽象的,又因为我们的配置文件是XML格式的,所以具体实现实在AbstractXmlApplicationConext中
- @Override
- protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
- // Create a new XmlBeanDefinitionReader for the given BeanFactory.
- XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
- // Configure the bean definition reader with this context's
- // resource loading environment.
- beanDefinitionReader.setResourceLoader(this);
- beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
- // Allow a subclass to provide custom initialization of the reader,
- // then proceed with actually loading the bean definitions.
- initBeanDefinitionReader(beanDefinitionReader);
- loadBeanDefinitions(beanDefinitionReader);
- }
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
这里创建了一个XmlBeanDefinitionReader 对象,它专门用来读取基于XML文件格式的BeanDefinition配置,接下来重载到loadBeanDefinitions(beanDefinitionReader);
- protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
- Resource[] configResources = getConfigResources();
- if (configResources != null) {
- reader.loadBeanDefinitions(configResources);
- }
- String[] configLocations = getConfigLocations();
- if (configLocations != null) {
- reader.loadBeanDefinitions(configLocations);
- }
- }
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
首先载入Resource对象用来定位资源,Resource对象的生成在ClassPathXmlApplicationContext 中setConfigLocations(configLocations)方法实现
然后调用XmlBeanDefinitionReader基类AbstractBeanDefinitionReader的loadBeanDefinitions方法
- public int loadBeanDefinitions(Resource[] resources) throws BeanDefinitionStoreException {
- Assert.notNull(resources, "Resource array must not be null");
- int counter = 0;
- for (Resource resource : resources) {
- counter += loadBeanDefinitions(resource);
- }
- return counter;
- }
public int loadBeanDefinitions(Resource[] resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
for (Resource resource : resources) {
counter += loadBeanDefinitions(resource);
}
return counter;
}
然后调用loadBeanDefinitions(resource)方法,此方法的具体实现在XmlBeanDefinitionReader 中
- public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
- return loadBeanDefinitions(new EncodedResource(resource));
- }
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
重载到
- public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
- Assert.notNull(encodedResource, "EncodedResource must not be null");
- if (logger.isInfoEnabled()) {
- logger.info("Loading XML bean definitions from " + encodedResource.getResource());
- }
- Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
- if (currentResources == null) {
- currentResources = new HashSet<EncodedResource>(4);
- this.resourcesCurrentlyBeingLoaded.set(currentResources);
- }
- if (!currentResources.add(encodedResource)) {
- throw new BeanDefinitionStoreException(
- "Detected recursive loading of " + encodedResource + " - check your import definitions!");
- }
- try {
- 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 (IOException ex) {
- throw new BeanDefinitionStoreException(
- "IOException parsing XML document from " + encodedResource.getResource(), ex);
- }
- finally {
- currentResources.remove(encodedResource);
- if (currentResources.isEmpty()) {
- this.resourcesCurrentlyBeingLoaded.set(null);
- }
- }
- }
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected recursive loading of " + encodedResource + " - check your import definitions!");
}
try {
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 (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.set(null);
}
}
}
在此类中主要是对输入流进行编码操作,然后调用doLoadBeanDefinitions(inputSource, encodedResource.getResource())方法
5.XmlBeanDefinitionReader将载入工作交给W3C的dom
因为读入的文件是XML格式的,所以底层的实现肯定是要和W3C的dom结构打交道
doLoadBeanDefinitions(inputSource, encodedResource.getResource())方法正式引入dom
- protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
- throws BeanDefinitionStoreException {
- try {
- int validationMode = getValidationModeForResource(resource);
- Document doc = this.documentLoader.loadDocument(
- inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
- return registerBeanDefinitions(doc, resource);
- }
- catch (BeanDefinitionStoreException ex) {
- throw ex;
- }
- catch (SAXParseException ex) {
- throw new XmlBeanDefinitionStoreException(resource.getDescription(),
- "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
- }
- catch (SAXException ex) {
- throw new XmlBeanDefinitionStoreException(resource.getDescription(),
- "XML document from " + resource + " is invalid", ex);
- }
- catch (ParserConfigurationException ex) {
- throw new BeanDefinitionStoreException(resource.getDescription(),
- "Parser configuration exception parsing XML from " + resource, ex);
- }
- catch (IOException ex) {
- throw new BeanDefinitionStoreException(resource.getDescription(),
- "IOException parsing XML document from " + resource, ex);
- }
- catch (Throwable ex) {
- throw new BeanDefinitionStoreException(resource.getDescription(),
- "Unexpected exception parsing XML document from " + resource, ex);
- }
- }
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
int validationMode = getValidationModeForResource(resource);
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
在此方法中生成了Document类的对象,下一步是进行对象的注册,registerBeanDefinitions(doc, resource)方法
- public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
- // Read document based on new BeanDefinitionDocumentReader SPI.
- BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
- int countBefore = getRegistry().getBeanDefinitionCount();
- documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
- return getRegistry().getBeanDefinitionCount() - countBefore;
- }
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// Read document based on new BeanDefinitionDocumentReader SPI.
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
此方法统计了注册的BeanDefinition的个数,返回一个int值,而具体的注册工作在BeanDefinitionDocumentReader 接口的实现类DefaultBeanDefinitionDocumentReader 中registerBeanDefinitions(doc, createReaderContext(resource))方法实现
6.BeanDefinitionDocumentReader将载入工作交给代理类BeanDefinationParserDelegate
DefaultBeanDefinitionDocumentReader的registerBeanDefinitions(doc, createReaderContext(resource))方法
- public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
- this.readerContext = readerContext;
- logger.debug("Loading bean definitions");
- Element root = doc.getDocumentElement();
- BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
- preProcessXml(root);
- parseBeanDefinitions(root, delegate);
- postProcessXml(root);
- }
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
preProcessXml(root);
parseBeanDefinitions(root, delegate);
postProcessXml(root);
}
其中首先得到dom结构的根,然后由根进行分析
然后引入BeanDefinitionParserDelegate 代理类对dom结构进行分析,调用parseBeanDefinitions(root, delegate)方法
- protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
- if (delegate.isDefaultNamespace(delegate.getNamespaceURI(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;
- String namespaceUri = delegate.getNamespaceURI(ele);
- if (delegate.isDefaultNamespace(namespaceUri)) {
- parseDefaultElement(ele, delegate);
- }
- else {
- delegate.parseCustomElement(ele);
- }
- }
- }
- }
- else {
- delegate.parseCustomElement(root);
- }
- }
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(delegate.getNamespaceURI(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;
String namespaceUri = delegate.getNamespaceURI(ele);
if (delegate.isDefaultNamespace(namespaceUri)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
其中最主要的操作是在调用parseDefaultElement(ele, delegate)方法中进行
- private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
- if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
- importBeanDefinitionResource(ele);
- }
- else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
- processAliasRegistration(ele);
- }
- else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
- processBeanDefinition(ele, delegate);
- }
- }
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
}
从这个方法里面我们就能看出来底层元素的端倪了,首先判断Node是否为import节点,然后是alias节点,最后是bean节点,我们关心的是bean节点,processBeanDefinition(ele, delegate)方法
- protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
- BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
- if (bdHolder != null) {
- bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
- try {
- // Register the final decorated instance.
- BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
- }
- catch (BeanDefinitionStoreException ex) {
- getReaderContext().error("Failed to register bean definition with name '" +
- bdHolder.getBeanName() + "'", ele, ex);
- }
- // Send registration event.
- getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
- }
- }
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
这里首先由BeanDefinitionParserDelegate 生成BeanDefination的包装类BeanDefinitionHolder ,然后再进行一些修饰工作,这里把工作正式交给BeanDefinitionParserDelegate
7.BeanDefinitionParserDelegate 中的解析工作
BeanDefinition的解析主要在BeanDefinitionParserDelegate 的parseBeanDefinitionElement(ele)方法中进行,重载到
- public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
- String id = ele.getAttribute(ID_ATTRIBUTE);
- String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
- List<String> aliases = new ArrayList<String>();
- if (StringUtils.hasLength(nameAttr)) {
- String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS);
- aliases.addAll(Arrays.asList(nameArr));
- }
- String beanName = id;
- if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
- beanName = aliases.remove(0);
- if (logger.isDebugEnabled()) {
- logger.debug("No XML 'id' specified - using '" + beanName +
- "' as bean name and " + aliases + " as aliases");
- }
- }
- if (containingBean == null) {
- checkNameUniqueness(beanName, aliases, ele);
- }
- AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
- if (beanDefinition != null) {
- if (!StringUtils.hasText(beanName)) {
- try {
- if (containingBean != null) {
- beanName = BeanDefinitionReaderUtils.generateBeanName(
- beanDefinition, this.readerContext.getRegistry(), true);
- }
- else {
- beanName = this.readerContext.generateBeanName(beanDefinition);
- // Register an alias for the plain bean class name, if still possible,
- // if the generator returned the class name plus a suffix.
- // This is expected for Spring 1.2/2.0 backwards compatibility.
- String beanClassName = beanDefinition.getBeanClassName();
- if (beanClassName != null &&
- beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
- !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
- aliases.add(beanClassName);
- }
- }
- if (logger.isDebugEnabled()) {
- logger.debug("Neither XML 'id' nor 'name' specified - " +
- "using generated bean name [" + beanName + "]");
- }
- }
- catch (Exception ex) {
- error(ex.getMessage(), ele);
- return null;
- }
- }
- String[] aliasesArray = StringUtils.toStringArray(aliases);
- return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
- }
- return null;
- }
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
这个方法首先得到元素的name和id以及别名属性,然后再生成底层的AbstractBeanDefinition对象将它们包装生成BeanDefinitionHolder,其中包括bean的名称,别名,以及BeanDefinition,返回给上层方法
核心在于生成BeanDefinition的parseBeanDefinitionElement(ele, beanName, containingBean)方法
- public AbstractBeanDefinition parseBeanDefinitionElement(
- Element ele, String beanName, BeanDefinition containingBean) {
- this.parseState.push(new BeanEntry(beanName));
- String className = null;
- if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
- className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
- }
- try {
- String parent = null;
- if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
- parent = ele.getAttribute(PARENT_ATTRIBUTE);
- }
- AbstractBeanDefinition bd = createBeanDefinition(className, parent);
- parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
- bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
- parseMetaElements(ele, bd);
- parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
- parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
- parseConstructorArgElements(ele, bd);
- parsePropertyElements(ele, bd);
- parseQualifierElements(ele, bd);
- bd.setResource(this.readerContext.getResource());
- bd.setSource(extractSource(ele));
- return bd;
- }
- catch (ClassNotFoundException ex) {
- error("Bean class [" + className + "] not found", ele, ex);
- }
- catch (NoClassDefFoundError err) {
- error("Class that bean class [" + className + "] depends on not found", ele, err);
- }
- catch (Throwable ex) {
- error("Unexpected failure during bean definition parsing", ele, ex);
- }
- finally {
- this.parseState.pop();
- }
- return null;
- }
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
parseConstructorArgElements(ele, bd);
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
这个方法我们看起来一目了然,全部都是bean节点中的配置信息
首先得到class的名字,然后得到继承的parent的名字,然后是meta节点,look-up节点,replaced-method节点,构造函数设置节点,最后是比较复杂的property节点,我们继续分析比较复杂的property节点的解析,parsePropertyElements(ele, bd)方法
- public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
- NodeList nl = beanEle.getChildNodes();
- for (int i = 0; i < nl.getLength(); i++) {
- Node node = nl.item(i);
- if (node instanceof Element && nodeNameEquals(node, PROPERTY_ELEMENT)) {
- parsePropertyElement((Element) node, bd);
- }
- }
- }
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element && nodeNameEquals(node, PROPERTY_ELEMENT)) {
parsePropertyElement((Element) node, bd);
}
}
}
将bean节点的子元素逐个取出判断是否为property节点,然后进行解析,parsePropertyElement((Element) node, bd)方法
- public void parsePropertyElement(Element ele, BeanDefinition bd) {
- String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
- if (!StringUtils.hasLength(propertyName)) {
- error("Tag 'property' must have a 'name' attribute", ele);
- return;
- }
- this.parseState.push(new PropertyEntry(propertyName));
- try {
- if (bd.getPropertyValues().contains(propertyName)) {
- error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
- return;
- }
- Object val = parsePropertyValue(ele, bd, propertyName);
- PropertyValue pv = new PropertyValue(propertyName, val);
- parseMetaElements(ele, pv);
- pv.setSource(extractSource(ele));
- bd.getPropertyValues().addPropertyValue(pv);
- }
- finally {
- this.parseState.pop();
- }
- }
public void parsePropertyElement(Element ele, BeanDefinition bd) {
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
if (!StringUtils.hasLength(propertyName)) {
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}
解析的主要过程,首先判断是否重复,如果重复抛出异常,然后对property节点内部进行解析,最后加入到bean节点信息中,我们继续解析property节点内部,parsePropertyValue(ele, bd, propertyName)方法
- public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
- String elementName = (propertyName != null) ?
- "<property> element for property '" + propertyName + "'" :
- "<constructor-arg> element";
- // Should only have one child element: ref, value, list, etc.
- NodeList nl = ele.getChildNodes();
- Element subElement = null;
- for (int i = 0; i < nl.getLength(); i++) {
- Node node = nl.item(i);
- if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
- !nodeNameEquals(node, META_ELEMENT)) {
- // Child element is what we're looking for.
- if (subElement != null) {
- error(elementName + " must not contain more than one sub-element", ele);
- }
- else {
- subElement = (Element) node;
- }
- }
- }
- boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
- boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
- if ((hasRefAttribute && hasValueAttribute) ||
- ((hasRefAttribute || hasValueAttribute) && subElement != null)) {
- error(elementName +
- " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
- }
- if (hasRefAttribute) {
- String refName = ele.getAttribute(REF_ATTRIBUTE);
- if (!StringUtils.hasText(refName)) {
- error(elementName + " contains empty 'ref' attribute", ele);
- }
- RuntimeBeanReference ref = new RuntimeBeanReference(refName);
- ref.setSource(extractSource(ele));
- return ref;
- }
- else if (hasValueAttribute) {
- TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
- valueHolder.setSource(extractSource(ele));
- return valueHolder;
- }
- else if (subElement != null) {
- return parsePropertySubElement(subElement, bd);
- }
- else {
- // Neither child element nor "ref" or "value" attribute found.
- error(elementName + " must specify a ref or value", ele);
- return null;
- }
- }
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
String elementName = (propertyName != null) ?
"<property> element for property '" + propertyName + "'" :
"<constructor-arg> element";
// Should only have one child element: ref, value, list, etc.
NodeList nl = ele.getChildNodes();
Element subElement = null;
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
!nodeNameEquals(node, META_ELEMENT)) {
// Child element is what we're looking for.
if (subElement != null) {
error(elementName + " must not contain more than one sub-element", ele);
}
else {
subElement = (Element) node;
}
}
}
boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
if ((hasRefAttribute && hasValueAttribute) ||
((hasRefAttribute || hasValueAttribute) && subElement != null)) {
error(elementName +
" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
}
if (hasRefAttribute) {
String refName = ele.getAttribute(REF_ATTRIBUTE);
if (!StringUtils.hasText(refName)) {
error(elementName + " contains empty 'ref' attribute", ele);
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName);
ref.setSource(extractSource(ele));
return ref;
}
else if (hasValueAttribute) {
TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
valueHolder.setSource(extractSource(ele));
return valueHolder;
}
else if (subElement != null) {
return parsePropertySubElement(subElement, bd);
}
else {
// Neither child element nor "ref" or "value" attribute found.
error(elementName + " must specify a ref or value", ele);
return null;
}
}
property节点主要是value和ref属性的配置,所以此方法首先是配置以上两个属性,然后是分析property节点的子元素,parsePropertySubElement(subElement, bd)方法,重载到
- public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
- if (!isDefaultNamespace(getNamespaceURI(ele))) {
- return parseNestedCustomElement(ele, bd);
- }
- else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
- BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
- if (nestedBd != null) {
- nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
- }
- return nestedBd;
- }
- else if (nodeNameEquals(ele, REF_ELEMENT)) {
- // A generic reference to any name of any bean.
- String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
- boolean toParent = false;
- if (!StringUtils.hasLength(refName)) {
- // A reference to the id of another bean in the same XML file.
- refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
- if (!StringUtils.hasLength(refName)) {
- // A reference to the id of another bean in a parent context.
- refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
- toParent = true;
- if (!StringUtils.hasLength(refName)) {
- error("'bean', 'local' or 'parent' is required for <ref> element", ele);
- return null;
- }
- }
- }
- if (!StringUtils.hasText(refName)) {
- error("<ref> element contains empty target attribute", ele);
- return null;
- }
- RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
- ref.setSource(extractSource(ele));
- return ref;
- }
- else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
- return parseIdRefElement(ele);
- }
- else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
- return parseValueElement(ele, defaultValueType);
- }
- else if (nodeNameEquals(ele, NULL_ELEMENT)) {
- // It's a distinguished null value. Let's wrap it in a TypedStringValue
- // object in order to preserve the source location.
- TypedStringValue nullHolder = new TypedStringValue(null);
- nullHolder.setSource(extractSource(ele));
- return nullHolder;
- }
- else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
- return parseArrayElement(ele, bd);
- }
- else if (nodeNameEquals(ele, LIST_ELEMENT)) {
- return parseListElement(ele, bd);
- }
- else if (nodeNameEquals(ele, SET_ELEMENT)) {
- return parseSetElement(ele, bd);
- }
- else if (nodeNameEquals(ele, MAP_ELEMENT)) {
- return parseMapElement(ele, bd);
- }
- else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
- return parsePropsElement(ele);
- }
- else {
- error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
- return null;
- }
- }
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
if (!isDefaultNamespace(getNamespaceURI(ele))) {
return parseNestedCustomElement(ele, bd);
}
else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
if (nestedBd != null) {
nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
}
return nestedBd;
}
else if (nodeNameEquals(ele, REF_ELEMENT)) {
// A generic reference to any name of any bean.
String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
boolean toParent = false;
if (!StringUtils.hasLength(refName)) {
// A reference to the id of another bean in the same XML file.
refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
if (!StringUtils.hasLength(refName)) {
// A reference to the id of another bean in a parent context.
refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
toParent = true;
if (!StringUtils.hasLength(refName)) {
error("'bean', 'local' or 'parent' is required for <ref> element", ele);
return null;
}
}
}
if (!StringUtils.hasText(refName)) {
error("<ref> element contains empty target attribute", ele);
return null;
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
ref.setSource(extractSource(ele));
return ref;
}
else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
return parseIdRefElement(ele);
}
else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
return parseValueElement(ele, defaultValueType);
}
else if (nodeNameEquals(ele, NULL_ELEMENT)) {
// It's a distinguished null value. Let's wrap it in a TypedStringValue
// object in order to preserve the source location.
TypedStringValue nullHolder = new TypedStringValue(null);
nullHolder.setSource(extractSource(ele));
return nullHolder;
}
else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
return parseArrayElement(ele, bd);
}
else if (nodeNameEquals(ele, LIST_ELEMENT)) {
return parseListElement(ele, bd);
}
else if (nodeNameEquals(ele, SET_ELEMENT)) {
return parseSetElement(ele, bd);
}
else if (nodeNameEquals(ele, MAP_ELEMENT)) {
return parseMapElement(ele, bd);
}
else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
return parsePropsElement(ele);
}
else {
error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
return null;
}
}
这个方法内部也是一目了然,首先是配置property节点的内嵌bean,然后配置ref引用,然后是idref引用,接下来是内嵌的value元素,还有null元素,最后是一系列的复杂数据类型,array,list,set,map以及props。
到这里配置文件的载入基本上已经到底了,如果对以上元素的配置感兴趣的话,可以继续查看源代码。这里只是包含配置文件的载入过程,并不包括在Ioc容器中的注册,以及依赖注入的过程。