基于XmlBeanFactory加载bean分析:XmlBeanDefinitionReader(二)

 

 

查看一下XmlBeanDefinitionReader的类图结构java

一、BeanDefinitionReadernode

public interface BeanDefinitionReader {
    BeanDefinitionRegistry getRegistry();

    ResourceLoader getResourceLoader();

    ClassLoader getBeanClassLoader();

    BeanNameGenerator getBeanNameGenerator();

    int loadBeanDefinitions(Resource var1) throws BeanDefinitionStoreException;

    int loadBeanDefinitions(Resource... var1) throws BeanDefinitionStoreException;

    int loadBeanDefinitions(String var1) throws BeanDefinitionStoreException;

    int loadBeanDefinitions(String... var1) throws BeanDefinitionStoreException;
}

二、EnvironmentCapableweb

public interface EnvironmentCapable {
    Environment getEnvironment();
}

这个接口主要是获取系统环境变量等信息spring

三、AbstractBeanDefinitionReader BeanDefinition读取(抽象类)安全

public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable, BeanDefinitionReader {
    protected final Log logger = LogFactory.getLog(this.getClass());
    private final BeanDefinitionRegistry registry;
    private ResourceLoader resourceLoader;
    private ClassLoader beanClassLoader;
    private Environment environment;
    private BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator();

    protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        this.registry = registry;
        if(this.registry instanceof ResourceLoader) {
            this.resourceLoader = (ResourceLoader)this.registry;
        } else {
            this.resourceLoader = new PathMatchingResourcePatternResolver();
        }

        if(this.registry instanceof EnvironmentCapable) {
            this.environment = ((EnvironmentCapable)this.registry).getEnvironment();
        } else {
            this.environment = new StandardEnvironment();
        }

    }
}
//这里只列除了该类的主要参数以及构成函数,具体的实现须要查看源代码在实际逻辑分析时也会贴出部分关键源代码

RescoureLoader、Evnireonment等记录app

四、XmlBeanDefinitionReader函数

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
    public static final int VALIDATION_NONE = 0;
    public static final int VALIDATION_AUTO = 1;
    public static final int VALIDATION_DTD = 2;
    public static final int VALIDATION_XSD = 3;
    private static final Constants constants = new Constants(XmlBeanDefinitionReader.class);
    private int validationMode = 1;
    private boolean namespaceAware = false;
	//这里初始化的时候默认定义了DefaultBeanDefinitionDocumentReader
    private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
    private ProblemReporter problemReporter = new FailFastProblemReporter();
	//事件通知:默认实现了EmptyReaderEventListener监听器
    private ReaderEventListener eventListener = new EmptyReaderEventListener();
    private SourceExtractor sourceExtractor = new NullSourceExtractor();
    private NamespaceHandlerResolver namespaceHandlerResolver;
    private DocumentLoader documentLoader = new DefaultDocumentLoader();
    private EntityResolver entityResolver;
    private ErrorHandler errorHandler;
    private final XmlValidationModeDetector validationModeDetector;
    private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded;

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
        super(registry);
        this.errorHandler = new SimpleSaxErrorHandler(this.logger);
		//验证
        this.validationModeDetector = new XmlValidationModeDetector();
        this.resourcesCurrentlyBeingLoaded = new NamedThreadLocal("XML bean definition resources currently being loaded");
    }
}

-----------------------------------------具体分析--------------------------------------工具

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("myresource/applicationContext.xml"));
org.springframework.beans.factory.xml.XmlBeanFactory
public class XmlBeanFactory extends DefaultListableBeanFactory {
    private final XmlBeanDefinitionReader reader;

    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, (BeanFactory)null);
    }

    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
		//初始化了XmlBeanDefinitionReader读取器
        this.reader = new XmlBeanDefinitionReader(this);
		//并调用了loadBeanDefinitions方法
        this.reader.loadBeanDefinitions(resource);
    }
}
org.springframework.beans.factory.xml.XmlBeanDefinitionReader
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        return this.loadBeanDefinitions(new EncodedResource(resource));
}

这里咱们看到对Resource进行Encoded编码post

private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded;
实现
this.resourcesCurrentlyBeingLoaded = new NamedThreadLocal("XML bean definition resources currently being loaded");
//这里主要实现了对资源的加载
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if(this.logger.isInfoEnabled()) {
            this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }
        //这里获取当前线程的局部变量 咱们看到ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded里面存放的是一个set 资源信息例如[applicationContext.xml,myTest.xml等等多个xml信息等]
		//初始化的时候去尝试获取一下resourcesCurrentlyBeingLoaded,若是为空时,默认初始化了Set<EncodedResource>
		
        Object currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
        if(currentResources == null) {
            currentResources = new HashSet(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
		//若是加入失败时,才抛出异常,因此一般状况下都走的else流程,通常状况都能添加到当前线程
		//这里其实就是为了不循环加载,若是重复加载了相同的文件就会抛出异常
        if(!((Set)currentResources).add(encodedResource)) {
            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        } else {
            int var5;
            try {
			    //这里就是将resource转换为IntputStream
                InputStream ex = encodedResource.getResource().getInputStream();

                try {
                    InputSource inputSource = new InputSource(ex);
                    if(encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
					//具体执行#处理逻辑分明
                    var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                } finally {
                    ex.close();
                }
            } catch (IOException var15) {
                throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
            } finally {
                ((Set)currentResources).remove(encodedResource);
                if(((Set)currentResources).isEmpty()) {
                    this.resourcesCurrentlyBeingLoaded.remove();
                }

            }

            return var5;
        }
    }
//思考思考?
//加入resourcesCurrentlyBeingLoaded目的和意义
一、咱们看到resourcesCurrentlyBeingLoaded原本就是线程安全的由于使用了ThreadLocal,ThreadLocal存放的数据都是存放在Thread.ThreadLocalMap 中的。因此每一个线程会独享本身的数据。

this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());学习

//方法的具体实现
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
	try {
	    //经过InputSource和Resource加载Document对象
		//注:加载document里面设置了很复杂的逻辑处理一、包括对xml的验证处理以及解析(有兴趣能够单独了解)
		Document ex = this.doLoadDocument(inputSource, resource);
		//这里根据Document和Resource执行注册BeanDefinitions
		return this.registerBeanDefinitions(ex, resource);
	} catch (BeanDefinitionStoreException var4) {
		throw var4;
	} catch (SAXParseException var5) {
		throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);
	} catch (SAXException var6) {
		throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);
	} catch (ParserConfigurationException var7) {
		throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);
	} catch (IOException var8) {
		throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);
	} catch (Throwable var9) {
		throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);
	}
}

this.registerBeanDefinitions(ex, resource)

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    //建立一个BeanDefinition文档读取器,主要用于读取document文档【分支01】
	BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
	//获取注册前BeanDefinitionCount的数量
	int countBefore = this.getRegistry().getBeanDefinitionCount();
	//这里使用了委托#即本身不执行具体操做而是交给别人(BeanDefinitionDocumentReader documentReader)执行
	//职责分明啊(之后实际开发应用要多学习这种思想:扩展性很好的)
	documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
	//this.getRegistry().getBeanDefinitionCount()表示注册后BeanDefinitionCount的数量而后减去注册前BeanDefinitionCount的数量,就表示本次注册BeanDefinitionCount的数量
	return this.getRegistry().getBeanDefinitionCount() - countBefore;
}
【分支01】
private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
//这里执行很是简单就是将DefaultBeanDefinitionDocumentReader转化为BeanDefinitionDocumentReader
//经过类图结构咱们能够发现DefaultBeanDefinitionDocumentReader为BeanDefinitionDocumentReader的实现类而已。
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
	return (BeanDefinitionDocumentReader)BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
}

这里咱们学习到了BeanUtils.instantiateClass(this.documentReaderClass)工具类

就是将一个class转化为一个bean,这里很清楚确定用的是反射机制来实现。

documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));方法执行

由上面咱们分析出documentReader具体的实例对象就是DefaultBeanDefinitionDocumentReader

那么由此咱们就进入DefaultBeanDefinitionDocumentReader.registerBeanDefinitions继续研究具体执行了什么?

private XmlReaderContext readerContext;
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    //设置XmlReaderContext 便于其余方法直接能够读取
	this.readerContext = readerContext;
	this.logger.debug("Loading bean definitions");
	//获取document根节点
	Element root = doc.getDocumentElement();
	//调用(doRegisterBeanDefinitions)方法
	this.doRegisterBeanDefinitions(root);
}

this.doRegisterBeanDefinitions(root);

private BeanDefinitionParserDelegate delegate;
protected void doRegisterBeanDefinitions(Element root) {
    //这里尝试去获取delegate属性,可是经过分析源代码发如今初始化的时候并无设置delegate,因此这里获取到的delegate为null
	BeanDefinitionParserDelegate parent = this.delegate;
	//这里会建立一个delegate【分支02】
	this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
	/**
	* 这里说了一些什么事情呢?
	* 一、判断当前document的命名空间其实就是判断当前document的namespaceUri是否等于http://www.springframework.org/schema/beans,这里主要的目地就是只处理springbeans的xml
	* 二、判断document是否包含profile属性。这个属性的目的主要是分环境开发,好比dev,uat,prd_uat,prd等环境时,咱们须要根据不一样环境
	*   配置不一样的参数。这里能够经过这种方式来,而后在web.xml中<context-param><context-name>Spring.profile.active</context-name><context-value>dev/uat/prd_uat/prd</context-value></context-param>
	*   而后spring启动的时候就会根据这个配置来读取不一样的配置文件信息
	*
	*/
	if(this.delegate.isDefaultNamespace(root)) {
		String profileSpec = root.getAttribute("profile");
		if(StringUtils.hasText(profileSpec)) {
			String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
			if(!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
				if(this.logger.isInfoEnabled()) {
					this.logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
				}

				return;
			}
		}
	}
	//这里定义了一个处理器的模板方法
	this.preProcessXml(root);
	//根据当前document和BeanDefinitionParserDelegate delegate
	this.parseBeanDefinitions(root, this.delegate);
	//处理后的模板方法
	this.postProcessXml(root);
	this.delegate = parent;
}
//当前类未实现
protected void preProcessXml(Element root) {
}
////当前类未实现
protected void postProcessXml(Element root) {
}
//建立delegate【分支02】
protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
    //这里根据readerContext建立了一个BeanDefinitionParserDelegate对象
	BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
	//而后根据Element root和 BeanDefinitionParserDelegate parentDelegate 初始化了一些设置
	//这里到底作了一些什么事情呢?【就是将element转换为BeanDefinitionParserDelegate】也就是说就是将xml文件配置的bean信息,转化为BeanDefinitionParserDelegate对象
	delegate.initDefaults(root, parentDelegate);
	return delegate;
}
//【能够研究一下】BeanDefinitionParserDelegate它是一个单独的类,在程序中就表示某一个xml转换的java类而已

this.parseBeanDefinitions(root, this.delegate);

//经过以前分析咱们知道BeanDefinitionParserDelegate就是一个document处理器
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
	//【分支3】就是判断当前document是否拥有namespaceUri http://www.springframework.org/schema/beans
	if(delegate.isDefaultNamespace(root)) {
		//获取当前document的全部节点信息
		NodeList nl = root.getChildNodes();

		for(int i = 0; i < nl.getLength(); ++i) {
			Node node = nl.item(i);
			//这里只处理标签因此须要判断一下当前node是不是一个Element节点,若是是才继续执行,不然跳过执行
			if(node instanceof Element) {
				Element ele = (Element)node;
				//再次验证当前document是否拥有namespaceUri http://www.springframework.org/schema/beans若是包含就解析
				if(delegate.isDefaultNamespace(ele)) {
					this.parseDefaultElement(ele, delegate);
				} else {
					//若是不包含这里采用的是解析器模式,根据
					delegate.parseCustomElement(ele);
				}
			}
		}
	} else {
		delegate.parseCustomElement(root);
	}

}
//【分支3】BeanDefinitionParserDelegate中的方法
public boolean isDefaultNamespace(String namespaceUri) {
        return !StringUtils.hasLength(namespaceUri) || "http://www.springframework.org/schema/beans".equals(namespaceUri);
}

public boolean isDefaultNamespace(Node node) {
	return this.isDefaultNamespace(this.getNamespaceURI(node));
}

下面章节会对

一、delegate.parseCustomElement(ele);

二、this.parseDefaultElement(ele, delegate);

进行分开分析,由于里面实现太过复杂。写在一块儿不便理解

相关文章
相关标签/搜索