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

本文主要讲解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) {
    // 根标签NameSpace是http://www.springframework.org/schema/beans
    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 {
        // 非Beans根标签下的自定义标签`
        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;
    }
    /*
    1. readerContext对象在XmlBeanDefinitionReader.registerBeanDefinitions(Document doc, Resource resource)方法中创建;
    2. 创建readerContext时同时创建了NamespaceHandlerResolver对象;
    3. NamespaceHandlerResolver对象指定了自定义标签处理器类对应的配置文件位置;配置文件在:META-INF/spring.handlers;
    4. 配置文件是namespaceUri到类名称的映射,且处理类必需实现NamespaceHandler接口;
    5. resolve时会解析文件,加载配置文件,通过namespaceUri查找对应的类,并反射创建对象;
    5. 然后通过parse方法完成对文档节点的解析工作;
    6. spring 提供了NamespaceHandlerSupport抽象类提供了一种处理范例;
    7. -------
    8 .NamespaceHandlerSupport实现类反射生成类对象后会调用init()方法,且需要在init方法中指定每一个标签对应的处理类;
    8. 每一个标签的处理类应实现BeanDefinitionParser接口
    9. ContextNamespaceHandler就是一个NamespaceHandlerSupport的实现类,可以参考该类的实现方式。
     */
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
        error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
        return null;
    }
    // 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 @PreDestroy,@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());
    }
}
posted @ 2023-03-07 15:38  铵铵静静  阅读(107)  评论(0编辑  收藏  举报