Spring源码解析-refresh(二)-obtainFreshBeanFactory方法之自定义定义标签

上一篇文章中我们介绍了loadBeanDefinitions的对beanDefinition的加载工作,本次我们将研究其更深层次,如何解析自定义标签。
解析文件的过程:
1.加载spring.handlers配置文件
2.将配置文件内容加载到map结合中
3.根据指定的key去获取对应的处理器

如果需要自定义标签的话,需要做一下的步骤

  1. 创建一个对应的解析处理器类
  2. 创建一个普通的spring.handlers配置文件,让应用程序能够完成加载工作。
	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		// 以Resource的方式获得配置文件的资源位置
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		// 以String的形式获得配置文件的位置
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}
``
沿着代码的逻辑一路F7进来,进入到进行解析自定义标签的地方

```java
//类 DefaultBeanDefinitionDocumentReader
	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		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)) { // 如果namespace不是http://www.springframework.org/schema/beans
						parseDefaultElement(ele, delegate);
					}
					else {  // 本次我们研究的类, 解析自定义的标签
						delegate.parseCustomElement(ele); 
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

进入到parseCustomElement 方法中去 这里就是主要的解析代码中

	@Nullable
	public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
		// 获取对应的命名空间 其实就是Spring.handlers中key 值, 比如的测试用例中此处为http://abc.com/schema/dream
		String namespaceUri = getNamespaceURI(ele);
		if (namespaceUri == null) {
			return null;
		}
		// 根据命名空间找到对应的NamespaceHandlerspring
		 // 详细点就是 从获取的配置好的handler映射中,使用命名空间获取到对应的解析类,然后使用反射将类路径转换成类,然后将结果记录在缓存中
		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进行解析
		 //获取到对应的解析器,然后去解析类的doParse方法进行解析
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

以下是自定义标签的过程
新增的文件为:
在这里插入图片描述
在这里插入图片描述
附代码:

//自定义一个标签类Dream 省略get和set方法
public class Dream {
    private String dreamId;
    private String dreamName;
    private String howToDo;
    private String deadLine;
    private String id;
}
//自定义标签解析类DreamBeanDefinitionParser
package com.mashibing.testSelfTag;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

//自定义标签解析类
public class DreamBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

    @Override
    protected Class<?> getBeanClass(Element element) {
        return Dream.class;
    }

    @Override
    protected void doParse(Element element, BeanDefinitionBuilder builder) {
        //获取到标签的属性值
        String dreamId=element.getAttribute("dreamId");
        String dreamName=element.getAttribute("dreamName");
        String howToDo=element.getAttribute("howToDo");
        String deadLine=element.getAttribute("deadLine");
        if (StringUtils.hasText(dreamId)){
         builder.addPropertyValue("dreamId",dreamId);
        }
        if (StringUtils.hasText(dreamName)){
            builder.addPropertyValue("dreamName",dreamName);
        }
        if (StringUtils.hasText(howToDo)){
            builder.addPropertyValue("howToDo",howToDo);
        }
        if (StringUtils.hasText(deadLine)){
            builder.addPropertyValue("deadLine",deadLine);
        }
        //super.doParse(element, builder);
    }
}

//DreamNamespaceHandler 处理类
package com.mashibing.testSelfTag;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

public class DreamNamespaceHandler  extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("dream",new DreamBeanDefinitionParser());
    }
}

dream.xsd文件
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
        targetNamespace="http://abc.com/schema/dream"
        xmlns:tns="http://abc.com/schema/dream"
        elementFormDefault="qualified">
    <element name="dream">
        <complexType>
            <attribute name="id" type="string"/>
            <attribute name ="dreamId" type = "string"/>
            <attribute name ="dreamName" type = "string"/>
            <attribute name ="howToDo" type = "string"/>
            <attribute name ="deadLine" type="string"/>
        </complexType>
    </element>
</schema>

//Spring.hadlers文件
http\://abc.com/schema/dream=com.mashibing.testSelfTag.DreamNamespaceHandler

//Spring.schema文件
http\://abc.com/schema/dream.xsd=META-INF/dream.xsd

最后测试类:
public class TestSelfTag {
    public static void main(String[] args) {
        ApplicationContext context = new MyClassPathXmlApplicationContext("selftag.xml");
        User user=(User)context.getBean("testbean");
        System.out.println("username:"+user.getUsername()+"  "+"email:"+user.getEmail());
    }
}

最后我们看下执行的结果:
在这里插入图片描述

每天学习一点,坚持进步,加油

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`refresh()` 是 Spring 框架中的一个方法,它用于刷新应用程序上下文(ApplicationContext)以更新其内部状态。在 Spring 框架中,`refresh()` 方法是非常重要的,因为它负责完成应用程序上下文的初始化和配置,并准备好所有的单例 bean 以供使用。 下面是 `refresh()` 方法的主要流程: 1. 准备刷新过程中需要用到的变量和标志位; 2. 调用 `prepareRefresh()` 方法,进行一些预处理工作; 3. 调用 `obtainFreshBeanFactory()` 方法,创建 BeanFactory 并进行一些初始化工作; 4. 调用 `prepareBeanFactory(beanFactory)` 方法,对 BeanFactory 进行一些后续处理; 5. 调用 `postProcessBeanFactory(beanFactory)` 方法,对 BeanFactory 进行后置处理; 6. 调用 `invokeBeanFactoryPostProcessors(beanFactory)` 方法,执行 BeanFactoryPostProcessor 的 postProcessBeanFactory() 方法; 7. 调用 `registerBeanPostProcessors(beanFactory)` 方法,注册 BeanPostProcessor 实例; 8. 调用 `initMessageSource()` 方法,初始化 MessageSource 组件; 9. 调用 `initApplicationEventMulticaster()` 方法,初始化 ApplicationEventMulticaster 组件; 10. 调用 `onRefresh()` 方法,进行一些自定义的刷新工作; 11. 调用 `registerListeners()` 方法,注册事件监听器; 12. 调用 `finishBeanFactoryInitialization(beanFactory)` 方法,完成所有非延迟初始化的单例 bean 的初始化工作; 13. 调用 `finishRefresh()` 方法,完成上下文的刷新工作。 需要注意的是,`refresh()` 方法在执行过程中会涉及到很多细节,比如如何处理环境变量、如何处理自定义bean 定义、如何处理多个上下文之间的关系等等。如果需要深入了解 `refresh()` 方法的实现细节,可以查看 Spring 框架的源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值