`
QING____
  • 浏览: 2250742 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Commons-digester:规则引擎全实例

    博客分类:
  • JAVA
 
阅读更多

    Apache Commons-digester是一个非常便捷的XML-Java映射工具包,我们常用它作为规则引擎来使用,其中xml文件用来定义“规则”,通过digester解析之后,将会和javabean对象建立关系。其中struts/spring等第三方项目都使用digester作为xml-java映射工具;digester很好的实现了“xml定义规则”+“java业务处理”的桥接能力;今天我就给大家分享一下如何使用Digester工具设计“数据库分表”策略。

    Digester的API非常简单,在此就不再赘言,直接使用实例讲解。

 

一.XML与规则:

    你需要在XML文件中,定义“规则”,其中“规则”就类似于javabean的结构,告诉digester需要实例化什么javabean,不过xml格式必须是结构严谨的。【table-rules.xml

 

<?xml version='1.0'?>
<!-- 
	<rule id="this is the rule ID,it is required,cant be null.">
		<table>this is table name,such as 'order'.</table>
		<delimiter>
			as the meaning of label,it's delimiter,'_' is the default value,
			you can specify any readable words as delimiter.
		</delimiter>
		<size>
			the total number of table' shards.
			such as 64,it means there are 64 table-shards of the table.
		</size>
		<strategy>
			you can see something about RouteStrategyEnum.java.
		</strategy>
	</rule>
 -->
<rules>
	<rule id="order">
		<table>order</table>
		<strategy>hash_code_mod</strategy>
		<delimiter>_</delimiter>
		<size>256</size>
	</rule>
	<rule id="order_rule">
		<table>rder_rule</table>
		<strategy>number_mod</strategy>
		<delimiter>_</delimiter>
		<size>256</size>
	</rule>
</rules>

    此XML定义了一个root节点为“rules”,其子节点为“rule”;既然是“数据库分表”,那么每个rule我们可以认为是一种table的声明,其中<table>表示表的实际名称,<strategy>表示此表根据什么策略分表的(比如根据“用户名”hash,根据“订单ID”取模等);<delimiter>表示用于生成表全名时各个参数的“链接符”,比如“_”;<size>表示此table总共有多少个子表,比如256张子表,那么数据将根据“strategy”将数据散列到256张表中,最终子表的实际格式为:<table><delimiter><[size]>,例如“order”表根据“订单id”取模共有256张子表,那么每个子表的名称为order_0 ~ order_255.

 

二.XML与“规则”模式:【table-rule-pattern.xml

 

<?xml version="1.0"?>
<!DOCTYPE digester-rules 
  PUBLIC "-//Jakarta Apache //DTD digester-rules XML V1.0//EN" 
    "http://jakarta.apache.org/commons/digester/dtds/digester-rules.dtd">

<digester-rules>
  <pattern value="rules">
    <pattern value="rule">
      <object-create-rule classname="com.test.tableRule.object.TableRule"/>
      <set-properties-rule/>
      <set-next-rule methodname="put"/>
      <pattern value="table">
        <call-method-rule methodname="setTable" paramcount="0" paramtypes="java.lang.String"/>
      </pattern>
      <pattern value="size">
        <call-method-rule methodname="setSize" paramcount="0" paramtypes="java.lang.Integer"/>
      </pattern>
      <pattern value="type">
        <call-method-rule methodname="setType" paramcount="0" paramtypes="java.lang.String"/>
      </pattern>
      <pattern value="delimiter">
        <call-method-rule methodname="setDelimiter" paramcount="0" paramtypes="java.lang.String"/>
      </pattern>
      <pattern value="strategy">
        <call-method-rule methodname="setStrategy" paramcount="0" paramtypes="java.lang.String"/>
      </pattern>
    </pattern>
  </pattern>
</digester-rules>

    这个文件是告知digester如何解析和映射"table-rules.xml",它的主要作用就是声明XML与javabean映射关系。这个xml中的格式是已经约定的,你不能随意创建自己的节点元素。

    1) <pattern>的value属性为需要匹配的table-rules.xml中的元素节点名称,比如“rules”。

    2) <object-create-rule>表示“遇到”指定pattern的节点,将会创建一个java对象,此对象的为className类型。被创建的对象,将放在解析stack的顶部。

    3) <set-properties-rule>表示“对stack顶”的对象进行“属性赋值”操作,比如<rule>节点使用“set-properties”将会导致“id”属性的setter方法被调用。

    4) <set-next-rule>获取将“解析stack顶”的对象(stack.pop()),并执行“top-element”对象的“methodname”指定的方法;(实例中讲解)

    5) <call-method-rule>调用“解析stack顶”的对象的指定方法,参数值为当前pattern匹配的节点的值,paramcount为“方法的参数列表的个数”,0表示“只有一个参数”的方法,paramtypes为“方法的参数列表”的类型(","分割),如果paramtypes未声明,将会执行无参的方法。

 

三.Java实例:

    1) 测试类:

public class XmlRuleParseTestMain {
	
	public static void main(String[] args){
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		//ָclasspath
		Digester digester = DigesterLoader.createDigester(loader.getResource("table-rule-pattern.xml"));
		digester.setClassLoader(loader);
		final TableRulePool rulePool = TableRulePool.getInstance();
		digester.push(rulePool);//top-element
		try {
			digester.parse(loader.getResource("table-rules.xml"));
		}catch(Exception e){
			e.printStackTrace();
		}
		List<TableRule> rules = rulePool.getAllRules();
		for(TableRule rule : rules){
			System.out.println(rule.getId() + ":" + rule.getTable() + rule.getDelimiter() + rule.getSize());
		}
	}
}

    2) TableRulePool.java:用来保存XML解析的结果,所有的rules列表,它做为digester解析时的“top-element”,当解析table-rules.xml时,遇到“<rule>”节点时,将会创建TableRule对象,并根据<set-next-rule>中指定的put方法,将tableRule实例放入列表中。

/**
 * @author liuguanqing
 *	hold all tablerules,client can get anything from it
 */
public class TableRulePool{

	private final Map<String, TableRule> ruleMap = new ConcurrentHashMap<String, TableRule>(32);
	private static TableRulePool instance;
	private TableRulePool(){};
	
	public void put(TableRule rule) {
		if(rule.getId() == null) {
			throw new NullPointerException("Rule's ID cannt be null!");
		}
		if(rule.getDelimiter() == null){
			rule.setDelimiter(TableRule.DEFAULT_DELIMITER);
		}
		if(rule.getStrategy() == null){
			rule.setStrategy(TableRule.DEFAULT_STRATEGY);
		}
		rule.init();
		ruleMap.put(rule.getId(), rule);
	}
	
	public synchronized static TableRulePool  getInstance(){
		if(instance == null){
			instance = new TableRulePool();
		}
		return instance;
	}
	
	public TableRule getRule(String ruleId){
		return ruleMap.get(ruleId);
	}
	
	public List<TableRule> getAllRules(){
		return new ArrayList<TableRule>(ruleMap.values());
	}

} 

    3) TableRule.java:一个简单的POJO类,在解析table-rules.xml时,任何一个<rule>节点都会被映射成一个TableRule对象;在“规则模式”XML中,<object-create-rule>中指定。为了能够使用<set-properties-rule>,节点的属性(例如:id)需要有setter方法。<call-method-rule>中指定了执行tableRule实例的方法。

/**
 * @author liuguanqing
 *	full name : table + delimiter + size,such as "mall_order_256"
 */
public class TableRule implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = -5770269844973816977L;
	public static final String DEFAULT_DELIMITER = "_";//
	public static final String DEFAULT_STRATEGY = RouteStrategyEnum.NUMBER_MOD.getKey();//
	private String id;//
	//the strategy of data routing. such as "hash","number_mod"
	private String strategy;
	// prefix of the db-table,not included the "foot_number"
	private String table;
	private String delimiter;//
	private Integer size = 0;//the num of  subtables
	
	//key is foot_number of subtable
	//value is the fullname of subtable
	//such as,0:"order_0",1:"order_1"
	//I think it can be better than create a new subtable-name everytime.
	private Map<Integer,String> indexes = new HashMap<Integer,String>();
	public TableRule(){}
	public String getTable() {
		return table;
	}
	public void setTable(String table) {
		this.table = table;
	}
	public String getDelimiter() {
		return delimiter;
	}
	public void setDelimiter(String delimiter) {
		this.delimiter = delimiter;
	}
	public Integer getSize() {
		return size;
	}
	public void setSize(Integer size) {
		this.size = size;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getStrategy() {
		return strategy;
	}
	public void setStrategy(String strategy) {
		this.strategy = strategy;
	}
	
	/**
	 * build inner map
	 */
	public void init(){
		for(int i = 0; i < size; i++){
			indexes.put(i, table + delimiter + i);
		}
	}

	/**
	 *  route by key,return the fullname of subtable
	 * @param key
	 * @return
	 */
	public String getTable(Object key){
		if(key == null){
			throw new NullPointerException("route key cant be null1");
		}
		int index;
		if(key instanceof Number){
			index = ModStrategy.numberMod((Number)key, this.size);
		}else {
			index = ModStrategy.hashCodeMod(key.toString(), this.size);
		}
		return indexes.get(index);
	}
}

 

四.RuleSet:

    在上述例子中,我们看到,如果实现XML-Javabean的映射,需要2个xml文件:table-rules.xml定义“规则”列表,table-rule-pattern.xml定义“规则”解析的方式;digester还提供了兼容性的模式,使用java设定“规则”解析的方式,我们可以将不需要table-rule-pattern.xml。

 

    1) 测试类:

public class JavaRuleParseTestMain {
	
	public static void main(String[] args){
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		Digester digester = new Digester();
		digester.setClassLoader(loader);
		final TableRulePool rulePool = TableRulePool.getInstance();
		digester.push(rulePool);
		digester.addRuleSet(new ConfigRuleSet());
		try {
			digester.parse(loader.getResource("table-rules.xml"));
		}catch(Exception e){
			e.printStackTrace();
		}
		List<TableRule> rules = rulePool.getAllRules();
		for(TableRule rule : rules){
			System.out.println(rule.getId() + ":" + rule.getTable() + rule.getDelimiter() + rule.getSize());
		}
		//if you find something about username,you can do such as follow.
		String username = "zhangsan";
		TableRule orderRule = rulePool.getRule("order");
		System.out.println("Full tablename is:" + orderRule.getTable(username));
	}
	
}

    2) ConfigRuleSet.java:使用java设定“规则”解析方式,取代table-rule-pattern.xml

public class ConfigRuleSet extends RuleSetBase {

	@Override
	public void addRuleInstances(Digester digester) {
		//digester.push(TableRulePool.getInstance());
		digester.addObjectCreate("*/rule", "com.test.tableRule.object.TableRule");
		digester.addSetProperties("*/rule");
		digester.addSetNext("*/rule", "put");
		digester.addCallMethod("*/rule/table", "setTable",0,new String[]{"java.lang.String"});
		digester.addCallMethod("*/rule/size", "setSize",0,new String[]{"java.lang.Integer"});
		digester.addCallMethod("*/rule/type", "setSize",0,new String[]{"java.lang.String"});
		digester.addCallMethod("*/rule/delimiter", "setDelimiter",0,new String[]{"java.lang.String"});
		digester.addCallMethod("*/rule/strategy", "setStrategy",0,new String[]{"java.lang.String"});
		
	}	
}

    可以看出java代码和xml的声明的方式很类似,顺序也需要一样。

 

--END--

分享到:
评论

相关推荐

    commons-digester.jar

    8. **使用示例**: 在实际应用中,首先你需要创建一个 Digester实例,然后定义并添加RuleSet。接着,调用`parse()`方法,传入XML输入源,这样Digester就会开始解析XML并执行相应的Rule,创建和填充Java对象。 例如,...

    commons-digester-1.7.jar.zip

    Apache Commons Digester是一个Java库,主要用于解析XML文档,并根据预定义的规则将其转换为Java对象。在标题和描述中提到的"commons-digester-1.7.jar.zip"是一个包含Apache Commons Digester 1.7版本的压缩文件,...

    利用commons-digester解析xml

    2. **创建Digester实例**:然后,创建一个`Digester`对象,它是整个解析过程的控制器。 3. **定义规则**:使用`addRule`或`addSetProperties`等方法定义规则,将XML元素与Java对象的方法或属性关联起来。例如,`add...

    commons-digester-2.0.rar源文件及jar文件

    4. 规则集合(RuleSet):一组相关的规则,可以方便地一起应用到Digester实例上。 四、使用示例 一个简单的例子是创建一个XML配置文件,描述一个对象树,然后使用Digester来根据这个配置文件动态生成相应的Java对象...

    commons-digester.jar下载

    Commons-Digester是一个Java库,它提供了一组规则来解析XML文档,并将解析结果映射到Java对象。这个库在处理XML配置文件时特别有用,因为它可以自动化将XML元素和属性转换为对象的属性和方法调用。在给定的标题...

    commons-digester-2.1.jar.zip

    1. **创建Digester实例**:通过`new Digester()`创建。 2. **注册规则**:使用`addRuleSet`或`addRule`方法添加规则,定义XML结构和Java对象的对应关系。 3. **加载XML**:使用`parse`方法,传入XML输入流,开始...

    commons-digester

    7. **使用示例**:通常,使用Digester的第一步是创建一个新的`Digester`实例,然后通过`addRule`方法添加规则。接着,调用`parse`方法,传入XML输入流,开始解析并构建对象模型。 在实际应用中,Apache Commons ...

    使用Apache_Commons_Digester

    1. **创建 Digester 实例**:首先创建一个 `org.apache.commons.digester.Digester` 实例,并为其配置实现 `DigesterRule` 接口的对象。 2. **初始化 Stack**:使用 `Digester.push()` 方法将一个初始对象放入 ...

    Commons-digesterXML解析Demo

    规则通过`addRule()`方法添加到Digester实例中。例如,可以使用`CallMethodRule`来调用对象的方法,或者使用`SetPropertiesRule`来根据XML元素的属性设置对象的属性。规则通常与XML元素的路径(XPath)关联,例如`/...

    digester解析xml必备包.rar

    1. **初始化Digester**:创建一个`Digester`实例,并配置解析规则。这些规则可以使用`addRule`方法添加,指定XML元素与Java方法的映射。 2. **设置解析器**:将XML解析器(如SAXParser)与Digester关联,以便在解析...

    用到digester项目,直接解析存入数据库

    在解析XML过程中,首先需要创建一个Digester实例并设置解析规则。这些规则通常使用addRule方法定义,它们指示当遇到特定的XML元素时,应该执行哪个方法或如何设置Java对象的属性。一旦解析完成,生成的对象可以通过...

    digester 实例

    标题中的“digester 实例”指的是Apache Commons Digester库在Java开发中的应用。Apache Commons Digester是一个工具,它允许程序员指定一系列的规则,用于解析XML文档,并根据这些规则调用对象的方法来创建和配置...

    ssh常用工具jar包详解(很详细,有源码实例)

    commons-io.jar: ...commons-digester.jar: 它能方便地将XML文档所定义的元素转化为JAVA对象,其实它的用法有点象栈(当然内在的原理就是那个古老的东西,只是提供了更高一层的封装)。 具体见jar包......

    digester jar包大全

    这个路径被称为规则,可以使用`addRule`方法添加到Digester实例中。例如,如果XML中有`&lt;server&gt;&lt;database&gt;`这样的结构,我们可以设置规则,让Digester在遇到`&lt;database&gt;`元素时创建一个新的数据库对象,并将其添加到...

    commons-logging.jar 版本1.2

    Apache Commons Digester是一个用于解析XML文档并根据预定义的规则自动创建和配置对象的工具。在某些场景下,digester可能会依赖Commons Logging进行日志记录,以输出解析过程中的信息和错误。因此,"commons-...

    使用Digester解析XML文档示例

    3. **创建Digester实例**:在Java代码中创建Digester实例,并设置解析规则。 4. **解析XML文件**:使用Digester解析XML文件,并根据定义的规则创建Java对象。 #### 五、总结 通过上述介绍可以看出,Digester是一个...

Global site tag (gtag.js) - Google Analytics