• 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

  • 相关阅读:
    Building Java Projects with Gradle
    Vert.x简介
    Spring及Spring Boot 国内快速开发框架
    dip vs di vs ioc
    Tools (StExBar vs Cmder)which can switch to command line window on context menu in windows OS
    SSO的定义、原理、组件及应用
    ModSecurity is an open source, cross-platform web application firewall (WAF) module.
    TDD中测试替身学习总结
    Spring事务银行转账示例
    台式机(华硕主板)前面板音频接口(耳机和麦克风)均无声的解决办法
  • 原文地址:https://www.cnblogs.com/heben/p/7149413.html
Copyright © 2020-2023  润新知