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--
相关推荐
8. **使用示例**: 在实际应用中,首先你需要创建一个 Digester实例,然后定义并添加RuleSet。接着,调用`parse()`方法,传入XML输入源,这样Digester就会开始解析XML并执行相应的Rule,创建和填充Java对象。 例如,...
Apache Commons Digester是一个Java库,主要用于解析XML文档,并根据预定义的规则将其转换为Java对象。在标题和描述中提到的"commons-digester-1.7.jar.zip"是一个包含Apache Commons Digester 1.7版本的压缩文件,...
2. **创建Digester实例**:然后,创建一个`Digester`对象,它是整个解析过程的控制器。 3. **定义规则**:使用`addRule`或`addSetProperties`等方法定义规则,将XML元素与Java对象的方法或属性关联起来。例如,`add...
4. 规则集合(RuleSet):一组相关的规则,可以方便地一起应用到Digester实例上。 四、使用示例 一个简单的例子是创建一个XML配置文件,描述一个对象树,然后使用Digester来根据这个配置文件动态生成相应的Java对象...
Commons-Digester是一个Java库,它提供了一组规则来解析XML文档,并将解析结果映射到Java对象。这个库在处理XML配置文件时特别有用,因为它可以自动化将XML元素和属性转换为对象的属性和方法调用。在给定的标题...
1. **创建Digester实例**:通过`new Digester()`创建。 2. **注册规则**:使用`addRuleSet`或`addRule`方法添加规则,定义XML结构和Java对象的对应关系。 3. **加载XML**:使用`parse`方法,传入XML输入流,开始...
7. **使用示例**:通常,使用Digester的第一步是创建一个新的`Digester`实例,然后通过`addRule`方法添加规则。接着,调用`parse`方法,传入XML输入流,开始解析并构建对象模型。 在实际应用中,Apache Commons ...
1. **创建 Digester 实例**:首先创建一个 `org.apache.commons.digester.Digester` 实例,并为其配置实现 `DigesterRule` 接口的对象。 2. **初始化 Stack**:使用 `Digester.push()` 方法将一个初始对象放入 ...
规则通过`addRule()`方法添加到Digester实例中。例如,可以使用`CallMethodRule`来调用对象的方法,或者使用`SetPropertiesRule`来根据XML元素的属性设置对象的属性。规则通常与XML元素的路径(XPath)关联,例如`/...
1. **初始化Digester**:创建一个`Digester`实例,并配置解析规则。这些规则可以使用`addRule`方法添加,指定XML元素与Java方法的映射。 2. **设置解析器**:将XML解析器(如SAXParser)与Digester关联,以便在解析...
在解析XML过程中,首先需要创建一个Digester实例并设置解析规则。这些规则通常使用addRule方法定义,它们指示当遇到特定的XML元素时,应该执行哪个方法或如何设置Java对象的属性。一旦解析完成,生成的对象可以通过...
标题中的“digester 实例”指的是Apache Commons Digester库在Java开发中的应用。Apache Commons Digester是一个工具,它允许程序员指定一系列的规则,用于解析XML文档,并根据这些规则调用对象的方法来创建和配置...
commons-io.jar: ...commons-digester.jar: 它能方便地将XML文档所定义的元素转化为JAVA对象,其实它的用法有点象栈(当然内在的原理就是那个古老的东西,只是提供了更高一层的封装)。 具体见jar包......
这个路径被称为规则,可以使用`addRule`方法添加到Digester实例中。例如,如果XML中有`<server><database>`这样的结构,我们可以设置规则,让Digester在遇到`<database>`元素时创建一个新的数据库对象,并将其添加到...
Apache Commons Digester是一个用于解析XML文档并根据预定义的规则自动创建和配置对象的工具。在某些场景下,digester可能会依赖Commons Logging进行日志记录,以输出解析过程中的信息和错误。因此,"commons-...
3. **创建Digester实例**:在Java代码中创建Digester实例,并设置解析规则。 4. **解析XML文件**:使用Digester解析XML文件,并根据定义的规则创建Java对象。 #### 五、总结 通过上述介绍可以看出,Digester是一个...