• springbank 开发日志 Spring启动过程中对自定义标签的处理


    这篇随笔的许多知识来源于:http://www.importnew.com/19391.html

    之所以会去看这些东东,主要是希望能够模仿spring mvc的处理流程,做出一套合理的交易处理流程。

    之前已经根据网上查到的知识,做了一些尝试,只要按照如下流程,就可以使用自定义的命名空间:

    1.通过在spring的配置文件中配置自己的命名空间

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sb="http://www.springbank.com/schema/springbank"
        xsi:schemaLocation="  
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd  
         http://www.springbank.com/schema/springbank http://www.springbank.com/schema/springbank.xsd">
    
        <!-- 新建客户 -->
        <sb:transaction id="CreateOwner" action="CreateOwnerAction" template="TransTemplate"></sb:transaction>
    </beans>

    2.可以看到上面的xsd文件是一个web地址,我现在自然没有这个东东,所以要在spring.schemas这个文件中映射本地位置,而这个文件必须要放在CLASSPATH:META-INF下面

    http://www.springbank.com/schema/springbank.xsd=com/springbank/test/example/mytag/springbank.xsd

    但实际上可能是IDE比较傻,每次validate都会说找不到,但实际上运行起来的时候是能证明它是被找到的

    3.需要向spring注册我们的标签,和标签解析器,我们的标签。固定的套路,代码如下:

    public class SpringbankNamespaceHandlerSupport extends NamespaceHandlerSupport{
        private final Logger log = LoggerFactory.getLogger(getClass());
        @Override
        public void init() {
            registerBeanDefinitionParser("transaction", new TagTransactionBeanDefinitionParser());
        }
    }

    其中TagTransactionBeanDefinitionParser如下

    public class TagTransactionBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
        private final Logger log = LoggerFactory.getLogger(getClass());
        
        @Override
        protected Class<?> getBeanClass(Element element) {
            return Transaction.class;
        }
        protected void doParse(Element element, BeanDefinitionBuilder bean) {  
            String id = element.getAttribute("id");
            String action = element.getAttribute("action");
            String template = element.getAttribute("template");
      
            if (StringUtils.hasText(id)) {  
                bean.addPropertyValue("id", id);  
            }
            if (StringUtils.hasText(action)) {  
                bean.addPropertyValue("action", action);  
            }
            if (StringUtils.hasText(template)) {  
                bean.addPropertyValue("template", template);
            }
        } 
    }

    最后是我的测试类:

    public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("com/springbank/test/example/mytag/applicationContext.xml");
            Transaction transaction = (Transaction)context.getBean("CreateOwner");
            System.out.println(transaction.getTemplate());
        }

    输出:

    Jul 11, 2017 3:57:22 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
    INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@49c2faae: startup date [Tue Jul 11 15:57:22 CST 2017]; root of context hierarchy
    Jul 11, 2017 3:57:22 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
    INFO: Loading XML bean definitions from class path resource [com/springbank/test/example/mytag/applicationContext.xml]
    Bean Transaction have been created: Transaction [id=null, template=null]
    TransTemplate

    做法就是这样的做法,但是如果我要搞一个<sb:annotation-driven>,又改怎么办呢?所以只知道做法就没有办法举一反三,必须要知道原理,所以我先来研究上面的原理,主要是为什么我自己定义的SpringbankNamespaceHandlerSupport 能够工作

    我是new了一个ClassPathXmlApplicationContext,然后看它一步一步怎么处理。

    在BeanDefinitionParserDelegate类中:

    public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
            String namespaceUri = getNamespaceURI(ele);
            NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
            if (handler == null) {
                error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
                return null;
            }
            return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
        }

    经过调试可以看到:

    另一方面我发现在

    org.springframework.context.annotation.ConfigurationClassParser

    里面有doProcessConfigurationClass这个方法,对一些注解进行了了处理。这里我还没有看懂

    另一方面,根据开头那边文章里的知识在ComponentScanBeanDefinitionParser类里的parse方法对

    <context:component-scan base-package="com.xxx" />

    进行了处理

    所以我有了一个想法,就是我搞的<sb:annotation-dvriven/>我也搞这样一个parser去处理,扫描指定的包下面的信息,然后放到一个list中,当请求来的时候,根据交易类型,去遍历这个list

  • 相关阅读:
    相似性算法研究
    CNN实战篇-手把手教你利用开源数据进行图像识别(基于keras搭建)
    主流NoSQL数据库的分析与选择
    CentOS7下防火墙相关命令
    Error:(10, 32) java: 程序包org.springframework.xxxl不存在
    Windows下IDEA上传码云push的时候出现push to origin/master was rejected
    SpringBoot配置mybatis使用的两种方式
    SpringBoot+Mybatis-plus测试时碰到的奇怪时区问题
    Java String 在拼接时的编译器优化
    Java Maven项目更新后jdk版本变为1.5
  • 原文地址:https://www.cnblogs.com/heben/p/7149413.html
Copyright © 2020-2023  润新知