一、软件版本
spring-framework-4.0.7.RELEASE-dist
jdk1.7.0.79
myeclipse9.1
二、DefaultListableBeanFactory和XmlBeanDefinitionReader
1、 DefaultListableBeanFactory
在spring4.0 源码分析 搭建简单的分析环境(一)中,获取bean实例的时候,LZ用了XmlBeanFactory,通过查看源码来分析一下,到底是用到了什么。
看一下XmlBeanFactory这个类:
XmlBeanFactory.java
package org.springframework.beans.factory.xml;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.io.Resource;
@Deprecated
@SuppressWarnings({"serial", "all"})
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
XmlBeanFactory类继承了DefaultListableBeanFactory类。看似XmlBeanFactory只是对两个类方法的封装。在上面XmlBeanFactory.java源码中,XmlBeanFactory类使用了XML读取器XmlBeanDefinitionReader。
DefaultListableBeanFactory.java
package org.springframework.beans.factory.support;
@SuppressWarnings("serial")
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
....
....
/**
* Create a new DefaultListableBeanFactory with the given parent.
* @param parentBeanFactory the parent BeanFactory
*/
public DefaultListableBeanFactory(BeanFactory parentBeanFactory) {
super(parentBeanFactory);
}
....
....
}
DefaultListableBeanFactory 继承了抽象类AbstractAutowireCapableBeanFactory并且实现了接口ConfigurableListableBeanFactory和BeanDefinitionRegistry和Serializable。此处先不说DefaultListableBeanFactory是整个bean加载的核心部分,是加载bean的默认实现。XmlBeanFactory类对DefaultListableBeanFactory这个类进行了部分的扩展,主要是用XmlBeanDefinitionReader来从XML文件中读取bean的配置。
2、 XmlBeanDefinitionReader
XML配置文件的读取时spring中的一个非常重要的功能。
XmlBeanDefinitionReader.java
package org.springframework.beans.factory.xml;
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
....
....
/**
* Create new XmlBeanDefinitionReader for the given bean factory.
* @param registry the BeanFactory to load bean definitions into,
* in the form of a BeanDefinitionRegistry
*/
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
/**
* Specify the {@link DocumentLoader} to use.
* <p>The default implementation is {@link DefaultDocumentLoader}
* which loads {@link Document} instances using JAXP.
*/
public void setDocumentLoader(DocumentLoader documentLoader) {
this.documentLoader = (documentLoader != null ? documentLoader : new DefaultDocumentLoader());
}
/**
* Specify the {@link BeanDefinitionDocumentReader} implementation to use,
* responsible for the actual reading of the XML bean definition document.
* <p>The default is {@link DefaultBeanDefinitionDocumentReader}.
* @param documentReaderClass the desired BeanDefinitionDocumentReader implementation class
*/
public void setDocumentReaderClass(Class<?> documentReaderClass) {
if (documentReaderClass == null || !BeanDefinitionDocumentReader.class.isAssignableFrom(documentReaderClass)) {
throw new IllegalArgumentException(
"documentReaderClass must be an implementation of the BeanDefinitionDocumentReader interface");
}
this.documentReaderClass = documentReaderClass;
}
@Override
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 cyclic 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.remove();
}
}
}
public int loadBeanDefinitions(InputSource inputSource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(inputSource, "resource loaded through SAX InputSource");
}
public int loadBeanDefinitions(InputSource inputSource, String resourceDescription)
throws BeanDefinitionStoreException {
return doLoadBeanDefinitions(inputSource, new DescriptiveResource(resourceDescription));
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
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);
}
}
....
....
}
抽象类AbstractBeanDefinitionReader.java
package org.springframework.beans.factory.support;
public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable, BeanDefinitionReader {
....
....
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
// Determine ResourceLoader to use.
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
}
else {
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
// Inherit Environment if possible
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
this.environment = new StandardEnvironment();
}
}
public final BeanDefinitionRegistry getBeanFactory() {
return this.registry;
}
@Override
public final BeanDefinitionRegistry getRegistry() {
return this.registry;
}
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public ResourceLoader getResourceLoader() {
return this.resourceLoader;
}
public void setBeanClassLoader(ClassLoader beanClassLoader) {
this.beanClassLoader = beanClassLoader;
}
@Override
public ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public Environment getEnvironment() {
return this.environment;
}
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new DefaultBeanNameGenerator());
}
@Override
public BeanNameGenerator getBeanNameGenerator() {
return this.beanNameGenerator;
}
@Override
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;
}
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
for (String location : locations) {
counter += loadBeanDefinitions(location);
}
return counter;
}
....
....
}
XmlBeanDefinitionReader通过继承自AbstractBeanDefinitionReader类中的protected AbstractBeanDefinitionReader(BeanDefinitionRegistryregistry) 方法将传入的参数做ResourceLoader转化成Resource。然后XmlBeanDefinitionReader通过public intloadBeanDefinitions(EncodedResource encodedResource)方法对Resource做流转化,接着通过protected intdoLoadBeanDefinitions(InputSource inputSource, Resource resource)方法对流做了Document文件转化,然后通过DefaultDocumentLoader类做解析。说的这么快,有点迷糊了,需要跟着spring的代码了。我想应该详细的挖掘一下每个小步骤的具体实现。努力