看文章之前 首先问自己几个问题:
1自定义标签解析是如何实现bean的解析和注册的
2自定义标签解析和默认标签解析有何不同
Spring中标签分为两种:
1.Spring默认的标签 如<bean id="account" class
2.自定义标签 如<aop:aspectj-autoproxy
对于不同的标签 有不同的处理方式,如下图所示:
前面我们已经学习了默认标签的解析,那我们今天主要来学习一下自定义标签解析
首先 进入BeanDefinitionParserDelegate#parseCustomElement(Element, BeanDefinition)方法
1根据获取的uri去通过DefaultNamespaceHandlerResolver#resolve方法来获取到对应的NamespaceHandler
我们来看下 DefaultNamespaceHandlerResolver的结构
通过DefaultNamespaceHandlerResolver我们发现,它本地维护了一个 uri 和对应的handler类全限定名的映射关系如下图所示:
Class handlerClass = ClassUtils.forName(className, this.classLoader);
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
通过类名实例化生成对应的NamespaceHandler 并init()进行初始化 然后将初始化的NamespaceHandler存入到映射handlerMappings中替换掉原来的类路径,方便后面的使用 也避免重复初始化
在看handler.parse(ele, new ParserContext(this.readerContext, this, containingBd))之前我先回顾一下
我的bean.xml是这样配置如下:
我现在以<context:component-scan basepackage="com.dfire.soa.practice.testTransation.service.impl"/>为列子:
点击handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)进入其实是进入了子类NamespaceHandlerSupport去实现了NamespaceHandler.parse()方法,如下图:
BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext)通过element的localName 获取 对应的BeanDefinitionParser(NamespaceHandlerSupport中本地其实有一个localName和对应解析器的映射关系:
private final Map<String,BeanDefinitionParser> parsers =new HashMap<>(); 如下图:
我们可以看到component-scan -> {ComponentScanBeanDefinitionParser@1622} ) 所以parser.parse(element, parserContext)其实就是调用的子类ComponentScanBeanDefinitionParser中的parse方法进行标签的解析 最终注册还是调用了DefaultListableBeanFactory#registerBeanDefinition进行bean的注册
1BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
2registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())
3org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition
其实总结下来自定义标签解析注册 就是通过namespaceuri获取到对应的NamespaceHandler,通过调用父类NamespaceHandlerSupport #parse 获取对应的BeanDefinitionParser解析器 对标签进行解析成BeanDefinitionHolder然后进行注册,其实注册最终都是调DefaultListableBeanFactory#registerBeanDefinition中的注册方法进行注册 ,所谓的注册bean 就是在DefaultListableBeanFactory 维护的beanDefinitionMap中存bean name 和对应的BeanDefinition的关联关系,注册后通知时间监听器 我注册好了!
网友评论