首页 > 编程语言 >spring源码02-xml配置文件解析过程

spring源码02-xml配置文件解析过程

时间:2023-03-07 15:44:40浏览次数:55  
标签:02 xml 配置文件 int 标签 源码 spring new public

本文主要讲解spring通过xml进行配置时对xml的加载和解析过程、自定义标签的处理,重点是流程,不说明详细细节;

一、创建ClassPathXmlApplicationContext对象

//创建容器,并启动容器
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
//其内部调用父类AbstractApplicationContext.refresh()方法

二、xml标签分类:
spring对标签的分类

  1. 内置标签,spring的内置标签只有一种,即http://www.springframework.org/schema/beans nameSpace下的标签,包括bean,beans,alis,import;其他spring提供的一些标签也都被认为是自定义标签;
  2. 自定义标签
    1. spring 提供的一些标签,例如:context,aop
    2. 三方提供的例如,dubbo,apollo
    3. 创建自己的标签

三、调用流程
refresh总共有13个核心方法,本次仅讲解对application.xml的加载、解析流程,也就是obtainFreshBeanFactory()方法;其他的方法作用可以参考上一篇博客
https://www.cnblogs.com/LonelyTraveler/p/17161323.html

由于spring的代码调用过程太繁琐,接下来只给出主要的核心代码,非核心代码会给出调用过程中方法签名

//AbstractApplicationContext 
public void refresh() throws BeansException, IllegalStateException {
      // 本方法内还包含了很多其他方法,但是与xml加载无关,忽略
      // 创建了一个DefaultListableBeanFactory,并对xml文件进行了加载,完成BeanDefition的注册
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
}
//AbstractApplicationContext
protected ConfigurableListableBeanFactory obtainFreshBeanFactory();
//AbstractRefreshableApplicationContext
protected final void refreshBeanFactory() throws BeansException {
    if (hasBeanFactory()) {
        destroyBeans();
	closeBeanFactory();
    }
    try {
        //创建beanFactory,而外部的Content对象其实是对工厂对象提供的Faced模式对象,提供了更强大的功能和更简便的使用方式
	DefaultListableBeanFactory beanFactory = createBeanFactory();
	beanFactory.setSerializationId(getId());
	customizeBeanFactory(beanFactory);
        //加载解析xml文件,创建BeanDefition对象,BeanDefition可以理解为对xml文件内配置信息的另一种存储格式
        //xml的配置方式和注解配置方式的配置信息不一致,为了有一个统一的bean创建过程
        //所以对不同配置方式产生的配置信息使用了一种统一的数据格式。
	loadBeanDefinitions(beanFactory);
	this.beanFactory = beanFactory;
    } 
    catch (IOException ex) {
	throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}
//AbstractXmlApplicationContext
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
	// Create a new XmlBeanDefinitionReader for the given BeanFactory.
  	//创建xml解析类
	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
		
  	//加载xml所需的一些数据
	// Configure the bean definition reader with this context's
	// resource loading environment.
	beanDefinitionReader.setEnvironment(this.getEnvironment());
	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);
  	//加载xml,创建BeanDefition对象
	loadBeanDefinitions(beanDefinitionReader);
}
//AbstractXmlApplicationContext
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader);
//AbstractBeanDefinitionReader
public int loadBeanDefinitions(String... locations);
public int loadBeanDefinitions(String location);

public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
    ResourceLoader resourceLoader = getResourceLoader();
	
    //此处resourceLoader是ResourcePatternResolver的子类
    if (resourceLoader instanceof ResourcePatternResolver) {
	// Resource pattern matching available.
	try {
            //PathMatchingResourcePatternResolver对象在容器启动过程中调用父类AbstractApplicationContext类构造方法时进行了初始化,该类完成对资源文件配置进行解析,获取实际资源文件的Resource对象
	    Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
            //加载xml,创建BeanDefition对象
	    int count = loadBeanDefinitions(resources);
	    ......
	    return count;
	}
    }
}
//AbstractBeanDefinitionReader
public int loadBeanDefinitions(Resource... resources);
//XmlBeanDefinitionReader
public int loadBeanDefinitions(Resource resource);
public int loadBeanDefinitions(EncodedResource encodedResource);
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) {
     ......
    //加载xml文件,转换为文档对象
    Document doc = doLoadDocument(inputSource, resource);
    //处理标签,创建BeanDefition对象,并注册到BeanFactory
    int count = registerBeanDefinitions(doc, resource);
    ......
}
//XmlBeanDefinitionReader
public int registerBeanDefinitions(Document doc, Resource resource) {
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    int countBefore = getRegistry().getBeanDefinitionCount();
    //createReaderContext 该方法创建XmlReaderContext对象;content包含了NamespaceHandlerResolver对象,其实际对象是DefaultNamespaceHandlerResolver,该类指定DEFAULT_HANDLER_MAPPINGS_LOCATION:"META-INF/spring.handlers" 参数,该参数后续用于加载自定义标签对应的处理类使用;当前可以忽略,使用时会再次说明
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
}
//DefaultBeanDefinitionDocumentReader
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext); 
protected void doRegisterBeanDefinitions(Element root) {
  //解析xml标签,创建BeanDefition对象
  parseBeanDefinitions(root, this.delegate);
}

//DefaultBeanDefinitionDocumentReader                                         
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
  //http://www.springframework.org/schema/beans 根标签NameSpace
    if (delegate.isDefaultNamespace(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;
			if (delegate.isDefaultNamespace(ele)) {
            //内置标签对bean,beans,alis,import的处理,不展开说明了,有需要的请自行debug
			    parseDefaultElement(ele, delegate);
			}
			else {
            //自定义标签处理
			    delegate.parseCustomElement(ele);
			}
		}
	    }
    }
     else {
        //其他自定义标签处理
        delegate.parseCustomElement(root);
    }
}                                         

四、自定义标签处理

//BeanDefinitionParserDelegate
public BeanDefinition parseCustomElement(Element ele);

//BeanDefinitionParserDelegate
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
		String namespaceUri = getNamespaceURI(ele);
		if (namespaceUri == null) {
			return null;
		}
//NamespaceHandlerResolver对象,在registerBeanDefinitions(Document doc, Resource resource)方法中创建,指定了自定义标签处理器对应的类,配置文件是:META-INF/spring.handlers,resolve时会解析文件,加载配置文件,转换成实际的类对象,需要实现NamespaceHandler接口,(反射生成类对象后会调用init()方法,且需要在init方法中指定每一个标签对应的处理类,该处理类需要实现BeanDefinitionParser接口,--非必需ContextNamespaceHandler处理类是此流程);例如:ContextNamespaceHandler类实现了对content标签的处理;
  //resolve方法通过namespaceUri查找到对应的NamespaceHandler对象
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
  	//调用NamespaceHandler的parse方法进行标签解析
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

五、spring内置的自定义标签处理器:NamespaceHandler

​ spring也提供一些比较重要的自定义标签处理器,例如:ContextNamespaceHandler ,AopNamespaceHandler;在这些类内部会注册一些非常重要的bean对象,这些对象实现了BeanFactoryPostProcess和BeanPostProcessor接口,spring的强大扩展能力都是基于这两个接口实现,简单列一下每个标签对应的处理类,具体对BeanFactoryPostProcess和BeanPostProcessor处理流程,请关注后续文章。

public class ContextNamespaceHandler extends NamespaceHandlerSupport {

	@Override
	public void init() {
    //properties配置文件加载相关
		registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
    //properties配置重写
		registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
    //注解的支持@Autowired @Value @Inject,@Resource @PostConstruct @PreDestory,@Required
		registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
    //启用对bean的扫描
		registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
    //下边的没有使用过,不太清楚
		registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
	}

}


public class AopNamespaceHandler extends NamespaceHandlerSupport {

	/**
	 * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
	 * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
	 * and '{@code scoped-proxy}' tags.
	 */
	@Override
	public void init() {
		// In 2.0 XSD as well as in 2.5+ XSDs
    //aop代理配置
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
    //开启aop注解支持
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

		// Only in 2.0 XSD: moved to context namespace in 2.5+
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
	}

}

标签:02,xml,配置文件,int,标签,源码,spring,new,public
From: https://www.cnblogs.com/LonelyTraveler/p/17161410.html

相关文章