本文主要讲解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) {
//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