BeanFactory beanFactory =
new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
User u = (User) beanFactory.getBean("u");
我们开始的第一步,一定是要读取XML文件,并将xml文件封装成JAVA对象。
那么Spring是如何读取配置文件的
ClassPathResource是Resource接口的子类实现类
Resource接口的作用:读取相关文件的内容 获得输入流
文件 ---xml .properties .txt ,网络中的资源,二进制流中,网络中,各种渠道获取内容,并转化为输入流,根据不同的需求来使用Resource不同的实现类
那么Java当中,以什么格式来体现xml文件呢?BeanDefinition
从这里开始执行
进入到方法内部,此处的reader为XmlBeanDefinitionReader,即我们的配置文件是由XmlBeanDefinitionReader进行读取解析的
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
/*参数2,考虑到父子容器的出现,事实上这是非常少见的*/
/*
* 由XmlBeanDefinitionReader读入resource解析
* */
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
我们进入loadBeanDefinitions方法
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
/*====================上面是日志打印=====================*/
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(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专门用于解析的工具类(Sax),不是Spring的*/
/*获得输入流之后,封装好解析类*/
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();
}
}
}
通过上述的代码我们发现,在此方法中,获得了输入流,封装好了SAX的解析类,进入了doLoadBeanDefinitions方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
/*Document==>和Spring没关系,是XML解析所封装的一个对象
* inputSource:Xml --> Document -->BeanDefinition
* */
Document doc = doLoadDocument(inputSource, resource);
/*因为Document也不是Spring的对象,Document只是作为一个中间产物,为了Spring开发方便,Spring最终还是会将其转换为BeanDefinition*/
int count = registerBeanDefinitions(doc, resource);
/*count:封装对象的个数*/
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
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);
}
}
我们发现上述的代码中,抛出了很多异常,真正有价值的是try中的代码。
通过解析,我们得到了一个Document类型的对象,是xml解析工具所封装的,为了Spring的使用方便,最终Spring会将其转化为BeanDefinition,此时这个只作为一个中间产物。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
/*创建解析器类的新实例*/
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
/*已有的注册Bean对象的个数*/
int countBefore = getRegistry().getBeanDefinitionCount();
/*进行注册*/
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
/*现有的-以前有的=增加的*/
return getRegistry().getBeanDefinitionCount() - countBefore;
}
再次进入方法,我们分析发现,其中最核心的代码是中间部分,进行BeanDefinition的注册
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
将doc中的element取出,element就是<beans>标签,我们进入这个方法
protected void doRegisterBeanDefinitions(Element root) {
/*root:对应的给定的根标记<beans>*/
// 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.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
/*处理<profile>标签*/
/*
设置环境
* <beans profile="dev"></beans>开发环境
* <beans profile="production"></beans>生产环境
* */
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
/*====================上面是设置环境================*/
preProcessXml(root);
/*=====================>核心<===========================*/
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
上述一部分代码在设置环境<profile>标签
* <beans profile="dev"></beans>开发环境
* <beans profile="production"></beans>生产环境
* */
我们进入parseBeanDefinitions(root, this.delegate)方法
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
/*解析<beans>子节点*/
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
/*解析基本标签*
<bean id="" class="" scope="" parent="" init-method=""
<property name value
</bean>
<bean id="" class="" scope="" parent="" init-method=""
<construt-arg>
</bean>
*/
parseDefaultElement(ele, delegate);
}
else {
/*解析自定义标签
* 自定义标签:应用了新的命名空间的标签,
* <context:propertyplace-holder
<context:component-scan
<tx:annotation-driven
<mvc:annotation-drvent
<aop:config
* */
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
我们进入解析基本标签的方法
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
/*分门别类的选择*/
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
/*<import>标签
* 引入其他配置文件
* */
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
/*<Ailas>别名标签,(一个类的小名)*/
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
/*内嵌的Beans标签,即<beans></beans>内部又嵌套了一个<beans/>*/
// recurse
doRegisterBeanDefinitions(ele);
}
}
注意最后一个else if,如果<beans>内部嵌套了<beans>标签,会再次进入doRegisterBeanDefinitions(ele);方法
我们进入<bean>标签的解析
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
/*
BeanDefinitionParserDelegate 解析器 将<Bean>标签解析成BeanDefinitionHolder Holder占位符
* BeanDefinitionHolder:BeanDefinition的包装 :Bean的名字(Id) + 别名 + beanDefinition,用着方便
* */
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
/*<bean>标签内部出现自定义标签*/
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
/*进行BeanDefinition的注册*/
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));
}
}
此处我们发现,成功的将输入流,转变为了BeanDefinition,但是Spring却将其封装为了BeanDefinitionHolder,BeanDefinitionHolder:BeanDefinition的包装 :Bean的名字(Id) + 别名 + beanDefinition,很显然,是为了后续处理更加方便。至此,我们完成了BeanDefinition的封装。