Apollo自定义标签学习

最近在学习使用携程的Apollo配置中心,看到Apollo的自定义标签,学习一下。
关于spring的自定义标签教程很多,这里就不赘述了,直接记录一下Apollo是怎么样利用自定义标签来注入属性的。

新建apollo-1.0.0.xsd文件

这个xsd就定义了一个config节点,然后下面定义了两个属性,namespaces,order,这两个属性就是应用id和加载顺序。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://www.ctrip.com/schema/apollo"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://www.ctrip.com/schema/apollo"
            elementFormDefault="qualified"
            attributeFormDefault="unqualified">

    <xsd:annotation>
        <xsd:documentation><![CDATA[ Namespace support for Ctrip Apollo Configuration Center. ]]></xsd:documentation>
    </xsd:annotation>

    <xsd:element name="config">
        <xsd:annotation>
            <xsd:documentation>
                <![CDATA[ Apollo configuration section to integrate with Spring.]]>
            </xsd:documentation>
        </xsd:annotation>
        <xsd:complexType>
            <xsd:attribute name="namespaces" type="xsd:string" use="optional">
                <xsd:annotation>
                    <xsd:documentation>
                        <![CDATA[
                            The comma-separated list of namespace names to integrate with Spring property sources.
                            If not specified, then default to application namespace.
                        ]]>
                    </xsd:documentation>
                </xsd:annotation>
            </xsd:attribute>
            <xsd:attribute name="order" type="xsd:int" use="optional">
                <xsd:annotation>
                    <xsd:documentation>
                        <![CDATA[
                            The order of the config, default to Ordered.LOWEST_PRECEDENCE, which is Integer.MAX_VALUE.
                            If there are properties with the same name in different apollo configs, the config with smaller order wins.
                        ]]>
                    </xsd:documentation>
                </xsd:annotation>
            </xsd:attribute>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>
定义xmlns节点

我们知道在spring的配置文件里面,都是通过定义xmlns来引用标签的,如:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:qt="http://www.imobpay.com/schema/qt"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
           http://www.springframework.org/schema/aop   
           http://www.springframework.org/schema/aop/spring-aop-3.2.xsd  
           http://www.springframework.org/schema/tx  
           http://www.springframework.org/schema/tx/spring-tx-3.2.xsd  
           http://www.springframework.org/schema/context  
           http://www.springframework.org/schema/context/spring-context-3.2.xsd
           http://www.imobpay.com/schema/qt http://www.imobpay.com/schema/qt.xsd"
       default-autowire="byName" default-lazy-init="false">

新建一个spring.schemas
这里的http\://www.ctrip.com/schema/apollo-1.0.0.xsd就是xmlns:qt配置需要的。

http\://www.ctrip.com/schema/apollo-1.0.0.xsd=/META-INF/apollo-1.0.0.xsd
http\://www.ctrip.com/schema/apollo.xsd=/META-INF/apollo-1.0.0.xsd
自定义标签的解析类
package com.ctrip.framework.apollo.spring.config;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import org.springframework.core.Ordered;
import org.w3c.dom.Element;

import com.ctrip.framework.apollo.core.ConfigConsts;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;

/**
 * @author Jason Song(song_s@ctrip.com)
 */
public class NamespaceHandler extends NamespaceHandlerSupport {
  private static final Splitter NAMESPACE_SPLITTER = Splitter.on(",").omitEmptyStrings().trimResults();

  @Override
  public void init() {
  //定义自定义标签的标签名config,这些写死了config,因此使用的时候只能是config,使用的时候一般是这样的<apollo:config>
    registerBeanDefinitionParser("config", new BeanParser());
  }

  static class BeanParser extends AbstractSingleBeanDefinitionParser {
  //这个方法就是返回一个bean,这个bean会被spring加载进去。
    @Override
    protected Class<?> getBeanClass(Element element) {
      return ConfigPropertySourcesProcessor.class;
    }
//是否生产ID,一般都是true,可以看注释。
    @Override
    protected boolean shouldGenerateId() {
      return true;
    }

    @Override
    protected void doParse(Element element, BeanDefinitionBuilder builder) {
//这段逻辑就比较简单了,就是解析自定义的标签,因为apollo只定义了一层标签,因此解析也比较简单,如果节点有子节点那解析就会复杂很多了,这里只是把namespaces标签的值取出来用","做了一个分割变成一个集合,然后判断order是否有值,没有就默认最小的。
//这里最关键的代码就是 PropertySourcesProcessor.addNamespaces(NAMESPACE_SPLITTER.splitToList(namespaces), order);这段代码了,这段代码就把namespace和order添加到PropertySourcesProcessor的一个内部属性里面了,这个内部属性就是一个常量map,下面这一点是PropertySourcesProcessor的方法。
==========================
 private static final Multimap<Integer, String> NAMESPACE_NAMES = LinkedHashMultimap.create();
 public static boolean addNamespaces(Collection<String> namespaces, int order) {
    return NAMESPACE_NAMES.putAll(order, namespaces);
  }
============================
      String namespaces = element.getAttribute("namespaces");
      //default to application
      if (Strings.isNullOrEmpty(namespaces)) {
        namespaces = ConfigConsts.NAMESPACE_APPLICATION;
      }

      int order = Ordered.LOWEST_PRECEDENCE;
      String orderAttribute = element.getAttribute("order");

      if (!Strings.isNullOrEmpty(orderAttribute)) {
        try {
          order = Integer.parseInt(orderAttribute);
        } catch (Throwable ex) {
          throw new IllegalArgumentException(
              String.format("Invalid order: %s for namespaces: %s", orderAttribute, namespaces));
        }
      }
      PropertySourcesProcessor.addNamespaces(NAMESPACE_SPLITTER.splitToList(namespaces), order);
    }
  }
}

新建spring.handlers文件

上面定义好自定义标签解析器之后,还需要使spring识别这个自定义解析器,新建spring.handlers,里面的文件内容就是这样的,后面的就是自定义的标签解析类。

http\://www.ctrip.com/schema/apollo=com.ctrip.framework.apollo.spring.config.NamespaceHandler

这样一个完整的自定义标签解析就算完成了,然后打成jar包,项目引用标签就能自动进行解析了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
使用 JavaScript 编写的记忆游戏(附源代码)   项目:JavaScript 记忆游戏(附源代码) 记忆检查游戏是一个使用 HTML5、CSS 和 JavaScript 开发的简单项目。这个游戏是关于测试你的短期 记忆技能。玩这个游戏 时,一系列图像会出现在一个盒子形状的区域中 。玩家必须找到两个相同的图像并单击它们以使它们消失。 如何运行游戏? 记忆游戏项目仅包含 HTML、CSS 和 JavaScript。谈到此游戏的功能,用户必须单击两个相同的图像才能使它们消失。 点击卡片或按下键盘键,通过 2 乘 2 旋转来重建鸟儿对,并发现隐藏在下面的图像! 如果翻开的牌面相同(一对),您就赢了,并且该对牌将从游戏中消失! 否则,卡片会自动翻面朝下,您需要重新尝试! 该游戏包含大量的 javascript 以确保游戏正常运行。 如何运行该项目? 要运行此游戏,您不需要任何类型的本地服务器,但需要浏览器。我们建议您使用现代浏览器,如 Google Chrome 和 Mozilla Firefox, 以获得更好、更优化的游戏体验。要玩游戏,首先,通过单击 memorygame-index.html 文件在浏览器中打开游戏。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值