spring源码02-xml配置文件解析过程
本文主要讲解spring通过xml进行配置时对xml的加载和解析过程、自定义标签的处理,重点是流程,不说明详细细节;
一、创建ClassPathXmlApplicationContext对象
//创建容器,并启动容器
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
//其内部调用父类AbstractApplicationContext.refresh()方法
二、xml标签分类:
spring对标签的分类
- 内置标签,spring的内置标签只有一种,即http://www.springframework.org/schema/beans nameSpace下的标签,包括bean,beans,alis,import;其他spring提供的一些标签也都被认为是自定义标签;
- 自定义标签
- spring 提供的一些标签,例如:context,aop
- 三方提供的,例如:dubbo,apollo
- 创建自己的标签
三、调用流程
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());
}
}
邮箱:quiet_learn@163.com
本文版权归作者和博客园共有,欢迎转载,转载请在文章明显位置注明作者及出处,谢谢!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南