??xml version="1.0" encoding="utf-8" standalone="yes"?>国产亚洲av片在线观看18女人,亚洲成熟丰满熟妇高潮XXXXX,91在线精品亚洲一区二区 http://m.tkk7.com/ericwang/zh-cn Sat, 10 May 2025 21:43:21 GMT Sat, 10 May 2025 21:43:21 GMT 60 理解ThreadLocal http://m.tkk7.com/ericwang/archive/2009/07/01/284913.htmlDion Dion Wed, 01 Jul 2009 04:15:00 GMT http://m.tkk7.com/ericwang/archive/2009/07/01/284913.html http://m.tkk7.com/ericwang/comments/284913.html http://m.tkk7.com/ericwang/archive/2009/07/01/284913.html#Feedback 0 http://m.tkk7.com/ericwang/comments/commentRss/284913.html http://m.tkk7.com/ericwang/services/trackbacks/284913.html ThreadLocal是什?/strong>
早在JDK 1.2的版本中提供java.lang.ThreadLocalQThreadLocal军_U程E序的ƈ发问题提供了一U新的思\。用这个工L可以很简z地~写Z的多线E程序?/p>
ThreadLocal很容易让人望文生义,惛_然地认ؓ是一?#8220;本地U程”。其实,ThreadLocalq不是一个ThreadQ而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些?/p>
当用ThreadLocall护变量ӞThreadLocal为每个用该变量的线E提供独立的变量副本Q所以每一个线E都可以独立地改变自q副本Q而不会媄响其它线E所对应的副本?/p>
从线E的角度看,目标变量p是线E的本地变量Q这也是cd?#8220;Local”所要表辄意思?/p>
U程局部变量ƈ不是Java的新发明Q很多语aQ如IBM IBM XL FORTRANQ在语法层面提供线E局部变量。在Java中没有提供在语言U支持,而是变相地通过ThreadLocal的类提供支持?/p>
所以,在Java中编写线E局部变量的代码相对来说要笨拙一些,因此造成U程局部变量没有在Java开发者中得到很好的普及?/p>
ThreadLocal的接口方?/p>
ThreadLocalcL口很单,只有4个方法,我们先来了解一下:
讄当前U程的线E局部变量的倹{?/p>
该方法返回当前线E所对应的线E局部变量?/p>
当前线E局部变量的值删除,目的是ؓ了减内存的占用Q该Ҏ是JDK 5.0新增的方法。需要指出的是,当线E结束后Q对应该U程的局部变量将自动被垃圑֛Ӟ所以显式调用该Ҏ清除U程的局部变量ƈ不是必须的操作,但它可以加快内存回收的速度?/p>
protected Object initialValue()
q回该线E局部变量的初始|该方法是一个protected的方法,昄是ؓ了让子类覆盖而设计的。这个方法是一个gq调用方法,在线E第1ơ调用get()或set(Object)时才执行Qƈ且仅执行1ơ。ThreadLocal中的~省实现直接q回一个null?/p>
值得一提的是,在JDK5.0中,ThreadLocal已经支持泛型Q该cȝcd已经变ؓThreadLocal<T>。APIҎ
也相应进行了调整Q新版本的APIҎ分别是void set(T value)、T get()以及T initialValue()?/p>
ThreadLocal是如何做Cؓ每一个线E维护变量的副本的呢Q其实实现的思\很简单:在ThreadLocalcM有一个MapQ用于存储每一个线E的变量副本QMap中元素的键ؓU程对象Q而值对应线E的变量副本。我们自己就可以提供一个简单的实现版本Q?/p>
代码清单 1 SimpleThreadLocal
public class SimpleThreadLocal {
private Map valueMap = Collections.synchronizedMap(new HashMap());
public void set(Object newValue) {
valueMap.put(Thread.currentThread(), newValue );①键为线E对象,gؓ本线E的变量副本
}
public Object get() {
Thread currentThread = Thread.currentThread();
Object o = valueMap.get(currentThread);②返回本U程对应的变?/strong>
if (o == null && !valueMap.containsKey(currentThread)) {③如果在Map中不存在Q放到Map
中保存v来?/strong>
o = initialValue();
valueMap.put(currentThread, o);
}
return o;
}
public void remove() {
valueMap.remove(Thread.currentThread());
}
public Object initialValue() {
return null;
}
}
虽然代码清单9?q个ThreadLocal实现版本昑־比较q稚Q但它和JDK所提供的ThreadLocalcd实现思\上是相近的?/p>
一个TheadLocal实例
下面Q我们通过一个具体的实例了解一下ThreadLocal的具体用方法?/p>
代码清单 2 SequenceNumber
package com.baobaotao.basic;
public class SequenceNumber {
?/strong>通过匿名内部c覆?/strong>ThreadLocal ?/strong>initialValue() ҎQ指定初始?/strong>
private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer> (){
public Integer initialValue(){
return 0;
}
};
?/strong>获取下一个序列?/strong>
public int getNextNum(){
seqNum.set(seqNum.get()+1);
return seqNum.get();
}
public static void main(String[] args)
{
SequenceNumber sn = new SequenceNumber();
?/strong> 3 个线E共?/strong>sn Q各自生序列号
TestClient t1 = new TestClient(sn );
TestClient t2 = new TestClient(sn );
TestClient t3 = new TestClient(sn );
t1.start();
t2.start();
t3.start();
}
private static class TestClient extends Thread
{
private SequenceNumber sn;
public TestClient(SequenceNumber sn) {
this.sn = sn;
}
public void run()
{
for (int i = 0; i < 3; i++) {④每个线E打?/strong>3 个序列?/strong>
System.out.println("thread["+Thread.currentThread().getName()+
"] sn["+sn.getNextNum() +"]");
}
}
}
}
通常我们通过匿名内部cȝ方式定义ThreadLocal的子c,提供初始的变量|如例子中①处所C。TestClientU程产生一l序列号Q?
在③处,我们生成3个TestClientQ它们共享同一个SequenceNumber实例。运行以上代码,在控制台上输Z下的l果Q?/p>
thread[Thread-2] sn[1]
thread[Thread-0] sn[1]
thread[Thread-1] sn[1]
thread[Thread-2] sn[2]
thread[Thread-0] sn[2]
thread[Thread-1] sn[2]
thread[Thread-2] sn[3]
thread[Thread-0] sn[3]
thread[Thread-1] sn[3]
考察输出的结果信息,我们发现每个U程所产生的序可焉׃n同一个SequenceNumber实例Q但它们q没有发生相互干扰的情况Q而是各自产生独立的序列号Q这是因为我们通过ThreadLocal为每一个线E提供了单独的副本?/p>
Thread同步机制的比?/p>
ThreadLocal和线E同步机制相比有什么优势呢QThreadLocal和线E同步机刉是ؓ了解军_U程中相同变量的讉K冲突问题?/p>
在同步机制中Q通过对象的锁机制保证同一旉只有一个线E访问变量。这时该变量是多个线E共享的Q用同步机制要求程序慎密地分析什么时候对变量q行dQ什么时候需要锁定某个对象,什么时候释攑֯象锁{繁杂的问题Q程序设计和~写隑ֺ相对较大?/p>
而ThreadLocal则从另一个角度来解决多线E的q发讉K。ThreadLocal会ؓ每一个线E提供一个独立的变量副本Q从而隔M多个U?
E对数据的访问冲H。因为每一个线E都拥有自己的变量副本,从而也没有必要对该变量进行同步了。ThreadLocal提供了线E安全的׃n对象Q在~?
写多U程代码Ӟ可以把不安全的变量封装进ThreadLocal?/p>
׃ThreadLocal中可以持有Q何类型的对象Q低版本JDK所提供的get()q回的是Object对象Q需要强制类型{换。但JDK
5.0通过泛型很好的解决了q个问题Q在一定程度地化ThreadLocal的用,代码清单 9 2׃用了JDK
5.0新的ThreadLocal<T>版本?/p>
概括h_对于多线E资源共享的问题Q同步机刉用了“以时间换I间”的方式,而ThreadLocal采用?#8220;以空间换旉”的方式。前者仅提供一份变量,让不同的U程排队讉KQ而后者ؓ每一个线E都提供了一份变量,因此可以同时讉K而互不媄响?/p>
Spring使用ThreadLocal解决U程安全问题
我们知道在一般情况下Q只有无状态的Bean才可以在多线E环境下׃nQ在Spring中,l大部分Bean都可以声明ؓsingleton作用
域。就是因为Spring对一些BeanQ如RequestContextHolder?
TransactionSynchronizationManager、LocaleContextHolder{)中非U程安全状态采?
ThreadLocalq行处理Q让它们也成为线E安全的状态,因ؓ有状态的Bean可以在多线E中׃n了?/p>
一般的Web应用划分为展现层、服务层和持久层三个层次Q在不同的层中编写对应的逻辑Q下层通过接口向上层开攑֊能调用。在一般情况下Q从接收h到返回响应所l过的所有程序调用都同属于一个线E,如图9?所C:
?/a>1同一U程贯通三?/p>
q样你就可以Ҏ需要,一些非U程安全的变量以ThreadLocal存放Q在同一ơ请求响应的调用U程中,所有关联的对象引用到的都是同一个变量?/p>
下面的实例能够体现SpringҎ状态Bean的改造思\Q?/p>
代码清单3 TopicDaoQ非U程安全
public class TopicDao {
private Connection conn;?/strong>一个非U程安全的变?/strong>
public void addTopic(){
Statement stat = conn.createStatement();?/strong>引用非线E安全变?/strong>
…
}
}
׃①处的conn是成员变量,因ؓaddTopic()Ҏ是非U程安全的,必须在用时创徏一个新TopicDao实例Q非singletonQ。下面用ThreadLocal对connq个非线E安全的“状?#8221;q行攚w:
代码清单4 TopicDaoQ线E安?/p>
import java.sql.Connection;
import java.sql.Statement;
public class TopicDao {
①用ThreadLocal保存Connection变量
private static ThreadLocal<Connection> connThreadLocal = new ThreadLocal<Connection>();
public static Connection getConnection(){
②如果connThreadLocal没有本线E对应的Connection创徏一个新的ConnectionQ?/strong>
q将其保存到U程本地变量中?/strong>
if (connThreadLocal.get() == null) {
Connection conn = ConnectionManager.getConnection();
connThreadLocal.set(conn);
return conn;
}else{
return connThreadLocal.get();③直接返回线E本地变?/strong>
}
}
public void addTopic() {
④从ThreadLocal中获取线E对应的Connection
Statement stat = getConnection().createStatement();
}
}
不同的线E在使用TopicDaoӞ先判断connThreadLocal.get()是否是nullQ如果是nullQ则说明当前U程q没有对
应的Connection对象Q这时创Z个Connection对象q添加到本地U程变量中;如果不ؓnullQ则说明当前的线E已l拥有了
Connection对象Q直接用就可以了。这P׃证了不同的线E用线E相关的ConnectionQ而不会用其它线E的
Connection。因此,q个TopicDao可以做到singleton׃n了?/p>
当然Q这个例子本w很_糙Q将Connection的ThreadLocal直接攑֜DAO只能做到本DAO的多个方法共享Connection?
不发生线E安全问题,但无法和其它DAOq同一个ConnectionQ要做到同一事务多DAO׃n同一ConnectionQ必d一个共同的外部c?
使用ThreadLocal保存Connection?/p>
结
ThreadLocal是解决线E安全问题一个很好的思\Q它通过为每个线E提供一个独立的变量副本解决了变量ƈ发访问的冲突问题。在很多情况
下,ThreadLocal比直接用synchronized同步机制解决U程安全问题更简单,更方便,且结果程序拥有更高的q发性?/p>
]]>[转]Drools in Action http://m.tkk7.com/ericwang/archive/2006/03/11/34787.htmlDion Dion Sat, 11 Mar 2006 02:02:00 GMT http://m.tkk7.com/ericwang/archive/2006/03/11/34787.html http://m.tkk7.com/ericwang/comments/34787.html http://m.tkk7.com/ericwang/archive/2006/03/11/34787.html#Feedback 0 http://m.tkk7.com/ericwang/comments/commentRss/34787.html http://m.tkk7.com/ericwang/services/trackbacks/34787.html 阅读全文
]]>[转]Drools的配|文?/title> http://m.tkk7.com/ericwang/archive/2006/03/11/34785.htmlDion Dion Sat, 11 Mar 2006 02:00:00 GMT http://m.tkk7.com/ericwang/archive/2006/03/11/34785.html http://m.tkk7.com/ericwang/comments/34785.html http://m.tkk7.com/ericwang/archive/2006/03/11/34785.html#Feedback 0 http://m.tkk7.com/ericwang/comments/commentRss/34785.html http://m.tkk7.com/ericwang/services/trackbacks/34785.html 前几天跟着写了一个简单的例子. 觉得Drools的配|也没有什? 今天在运行house的例子的时? 无论怎么? L异常: 没有定义的SMF. 昄没有扑ֈ我定义的drools.config文g. 官方|站上是q样写地: String droolsConfigProp = System.getProperty( "drools.conf" ); if ( droolsConfigProp != null ) { loadConfig( droolsConfigProp ); } ClassLoader cl = Thread.currentThread( ).getContextClassLoader( ); if ( cl == null ) { cl = getClass( ).getClassLoader( ); } Enumeration configUrls = cl.getResources( "META-INF/drools.conf" ); if ( !configUrls.hasMoreElements( ) ) { cl = getClass( ).getClassLoader( ); configUrls = cl.getResources( "META-INF/drools.conf" ); } if ( !configUrls.hasMoreElements( ) ) { cl = ClassLoader.getSystemClassLoader( ); configUrls = cl.getResources( "META-INF/drools.conf" ); } this.classLoader = cl; while ( configUrls.hasMoreElements( ) ) { URL configUrl = (URL) configUrls.nextElement( ); loadConfig( configUrl ); }
好像每一个旮旯里面都找了, Z么没有找到我的呢? System.getProperty指向的位|ƈ不一定和loadFromUrl位置一?呵呵. ]]> [转]Drools目?/title> http://m.tkk7.com/ericwang/archive/2006/03/11/34784.htmlDion Dion Sat, 11 Mar 2006 02:00:00 GMT http://m.tkk7.com/ericwang/archive/2006/03/11/34784.html http://m.tkk7.com/ericwang/comments/34784.html http://m.tkk7.com/ericwang/archive/2006/03/11/34784.html#Feedback 0 http://m.tkk7.com/ericwang/comments/commentRss/34784.html http://m.tkk7.com/ericwang/services/trackbacks/34784.html 内容提要
在本文的W一部分Q我讨则引擎如何帮助你从Y件的应用逻辑中分d商业规则逻辑Q以实现商业应用的灵zL。另外,我还介lJSRQ?4规则引擎
APIQ及其开源实现Drools目Q它是这一新技术的先驱。在W二部分Q我们将介绍一个规则引擎例子,q深入地研究Drools引擎及其JSRQ?4
扩展的复杂性?
Z么用规则引?/strong>
商业世界充满了关于变化的陈词滥调Q如M事物都会改变Q唯一不变的是变化{等。而在技术领域里Q情冉|好相反。我们仍然在试图解决30q前软g业中同样
的一堆问题-Q也许比30q前q要多的问题。在q去的十q_IT从业人员Ҏ在Y件方法学的大量文献中Q如快速Y件开发,极限~程Q敏捯Y件开发等Q它?
无一例外地强调灵zd变化的重要性?br> 但商业通常比开发团队所依赖的Y件过E和技术改变得更加q速。当商业{划人员试图重整IT部门Q以支持新的业务转型Ӟ仍然觉得很费劌Ӏ?/div>
Lost in Translation
虽然IT团队反应q速,但他们通常带来"电话效应"――ITl商业计划的执行带来的阻力和它带来的利益一样多。不q的是,在开发团队完全理解商业决{规?
q实C前,规则已经改变了。在软gq入市场前,它已l过时了Q需要进行重构以满新的业务需求。如果你是一个开发h员,你会知道我在说什么。再也没有比
在需求变动的情况下构造Y件让开发h员更沮的事情了。作Y件开发h员,你必L业务人员更了解业务,有时q要了解更多?br>
试想一下你是一位商业决{者。假如公司的成功依赖于你对于市场势敏锐的洞察力Q它常常帮助你领先于竞争者利用变化的市场环境获利。每天你都会得到更多?
好的市场信息Q但q不要紧。完成新产品开发可能需?Q?个月Q在此期_对于市场大胆和敏锐的z察和信息优势可能已l浪费了。而且Q当产品发布Ӟ有这
样几U可能:产品没有什么吸引h的特性,预算支Q过了品的最佛_布期限,或三者兼而有之?br>
情况可能q会更糟Q在完成产品开发时Q市场环境和规划产品开发时相比Q已l发生了Ҏ变化。现在你必须要遵守新的规则,你已l׃你的辚w优势Q而且?
计Y件的五h中的三h已经d了公司。你必须l接手的Ch重新讲解复杂的业务。如果事情不利Q你可能发现自己要对付一个缺文,q且你完全不了解的遗
留应用?br>
你的战略在哪出现了问题?你在哪里应该可以做到更好Q最q的轻量UY件过E,如极限编E,敏捷软g开发等都在自动单元试和Y件功能优先的重要性?
除此之外Q还有其他的原则Q你的开发团队可能也很熟悉,q些原则可以帮助他们寚w求的变动作出q速反应ƈ~短目的开发周期。这些原则的大多敎ͼ如系l分
解,多年前就已经出现Qƈ得到了Javaq_的支持(如JMX{)Q还有如面向对象和角色徏模,已经内徏在Java语言中?br>
但Java仍然是一门相当年ȝ语言Q而且Javaq_q远q没有完备。当前在JavaCQ一个引人注目的新技术是Q分d业决{者的商业决策逻辑和应
用开发者的技术决{,q把q些商业决策攑֜中心数据库,让它们能在运行时Q即商务旉Q可以动态地理和修攏V这是一个你值得考虑的策略?br>
Z么你的开发团队不得不象商业经理h一P在代码中包含复杂微妙的商业决{逻辑呢?你怎样才能向他们解释决{推理的微妙之处呢?你这样做是否谨慎呢??
能不是。象bottom
line一P某些东西在解释的q程中丢׃。ؓ什么要冒这L风险Q让应用代码或测试代码错误地表达你的商业决策逻辑呢?如果q样做的话,你怎样查它
们的正确性呢――难道你自己惛_习如何编E和~写试代码Q或者你的客户会Z试软gQ你一斚w要应付市场,一斚w要应付Y件代码,q实在太困难了?br>
如果能将q些商业决策规则集中地放在一个地方,以一U你可以理解的格式定义,让你可以直接理Q而不是散落在代码的各个角落,那该有多好。如果你能把商业
决策规则独立于你的Y件代码,让开发团队作出技术决{,你将会获得更多好处。你的项目开发周期会更短QY件对于变动的需求更灉|?/div>
规则引擎标准Java API
2003q?1月,JavaC通过了Java Rule Engine
API规范QJSRQ?4Q的最后草案。这个新的API让开发h员在q行时访问和执行规则有了l一的标准方式。随着新规范品实现的成熟和推向市场,开?
团队可以从应用代码中抽取出商业决策逻辑?br> q就需要新一代的理工具Q帮助商务经理h可以定义和细化Y件系l的行ؓ。不必通过开发过E来修改应用Qƈ假定可以得到正确的结果,l理人将可以随时Ҏ需要修改决{规则,q进行测试?br> 但这需要开发h员在设计pȝ时作出某些改变,q可以得到合适的开发工兗?/div>
分离商务和技术的x?/strong> q是一个非常简单的例子Q从l理人的角度Q说明如何分d务和技术的x炏V?br> 你管理着一个反向投资基金。你公司计算机系l的一部分用于分析股票hQ收益和每股净资Qƈ在需要时向你提出预警。这个计机pȝ的工作是Q识别出PE比率比市场^均g的股,q标记出来以便进一步的查?br> 你的IT部门拥有一大堆数据Qƈ开发了一pd你可以在规则中引用的单数据对象。现在,为简单v见,假设你是一名受q良好教育的Q了解技术的理人,你了解XML的基本知识,可以让你~写和修改简单的XML规则文g?br> 你的W一个规则是Q给道琼斯所有的股票估|q剔除P/E比率大于10的股(q有点过分简化,但这里只作ؓ一个例子)。保留下来的股票用来生一pd报表。对于这个简单的例子Q你的规则文件看h如下Q我们将会过头来讨论q个文g的结构)Q?/div>
<stock:overvalued> <stock:index> DJIA </stock:index> <stock:pe> over 10.0 </stock:pe> </stock:overvalued>
一个月后,你接C家巴西分析师公司的电话,雇䄦你的公司生成一pd巴西股市的报表,但他们有更严格的标准。而目前在巴西QP/E比率市场q_值是个位
敎ͼ因此你用来评估被市场低股的阈值需要改变。除了较低的P/E比率Q你的新客户q要求以Price-to-Book比率作ؓ参考标准?br> 你启动规则编辑器Qƈ修改规则以匹配新的评估条件。现在,规则引擎剔除巴西股市中P/E比率大于6.5Q以及Price to Book 比率于{于1的股。完成规则文件修改后Q看h如下Q?/div>
<stock:overvalued> <stock:index> Brazil </stock:index> <stock:pe> over 6.5 </stock:pe> <stock:pb> over 1.0 </stock:pb> </stock:overvalued>
你无需为此向开发团队作M解释。你无需{待他们开发或试E序。如果你的规则引擎的语义_强大Q让你描q工作数据,你可以随时按需修改商业规则?br> 如果限制因素是规则的定义语言和数据模型,你可以确信这两者将会标准化Qƈ出现先进的编辑器和工P以简化规则的定义Q保存和l护?br>
现在Q我希望你已l清楚以下的原则Q在q个例子中,哪只股票是否被选择是一个商务决{,而不是技术决{。决定将哪只股票交给你的分析师是l理人的逻辑
―?logic of the bottom
line"。经理h作出q些决策Qƈ可以按需定制应用。这些规则因此变成了一U控制界面,一U新的商业系l用L面?/div>
使用Rule开?/strong> 如果在这个应用场景中Q你是一个开发h员,你的工作会稍微轻松一些。一旦你拥有了一U用于分析股的规则语言Q你可以取出数据对象q交l规则引擎执行。我们将会到规则语言的讨论,但现在我们l刚才的例子?br>
你的pȝ一pd的stock
bean输入规则引擎。当规则执行后,你可以选出W合条g的股ƈ可以对它们作q一步处理。也许是把它们输入报表生成系l。分析师使用q些报表帮助他们?
析股市。同Ӟ老板也可能让你用新的技术分析工Pq用Dow理论预测股市的底部和剙?br> 规则引擎可以让你的系l变得更单,因ؓ你无需在代码中~写商务逻辑Q如怎样选择股票Q选择股票q程中奇怪的条gl合{。这些逻辑不再q入你的代码。你可以专注于数据模型?br> 现在可以q么认ؓQ通过从应用代码中剥离出易变的商业逻辑Q你的效率会更高。但凡是L例外――简单应用可能ƈ不能从规则系l中L。但如果你开发一个大型系l,有很多易变的商业逻辑Q你可以考虑在应用中集成规则引擎?br>
除了从应用代码中剥离出商业决{逻辑外,规则引擎q有其他用处。有时候你需要应用成百上千的规则q行决策Qƈ且有上千个对象和q些规则一起用。很难想?
有什么先q的人工引擎可以处理q种情况。遇到这U情况,你需要一个极快的决策法或是大型机。大型机q不便宜Q但你可以非怾宜的得到效率和可伸羃?
最好的法?/div>
Bob McWhirter的Drools目
现在Q我要介lDrools目QCharles Forgy Rete法的一个增强的Java语言实现。Drools是一个Bob
McWhirter开发的开源项目,攑֜The
Codehaus上。在我写q篇文章ӞDrools发表?.0-beata-14版。在CVS中,已完整地实现了JSR94 Rule
Engine APIq提供了单元试代码?br> Rete法是Charles
Forgy?979q发明的Q是目前用于生pȝ的效率最高的法Q除了私有的Rete
IIQ。Rete是唯一的,效率与执行规则数目无关的决策支持法。For the uninitiated, that means it can
scale to incorporate and execute hundreds of thousands of rules in a
manner which is an order of magnitude more efficient then the next best
algorithm。Rete应用于生产系l已l有很多q了Q但在Java开源Y件中q没有得到广泛应用(讨论Rete法的文参?a >http://herzberg.ca.sandia.gov/jess/docs/61/rete.html 。)?br>
除了应用了Rete核心法Q开源Y件License?00Q的Java实现之外QDroolsq提供了很多有用的特性。其中包括实CJSR94
API和创新的规则语义pȝQ这个语义系l可用来~写描述规则的语a。目前,Drools提供了三U语义模块――Python模块QJava模块?
Groovy模块。本文余下部分集中讨论JSR94 APIQ我在W二文章中讨论语义pȝ?br> 作ؓ使用javax.rules
API的开发h员,你的目标是构造一个RuleExecutionSet对象Qƈ在运行时通过它获得一个RuleSession对象。ؓ了简化这个过E,
我编写了一个规则引擎API的fa?adeQ可以用来解释代表Drools的DRL文g的InputStreamQƈ构造一?
RuleExecutionSet对象?br> 在上面提CDrools的三U语义模块,我接下来使用它们重新~写上面的例子XML规则文g。这个例子中我选择Java模块。用Java模块重新~写的规则文件如下:
<rule name="FlagAsUndervalued"> <parameter identifier="stock"> <java:class>org.codehaus.drools.example.Stock</java:class> </parameter> <java:condition>stock.getIndexName().equals("DJIA");</java:condition> <java:condition>stock.getPE() > 10 </java:condition> <java:consequence> removeObject(stock); ( 译注Q应该是retractObject(stock) ) </java:consequence> </rule> </rule-set>
现在的规则文件ƈ没有上面的简z明了。别担心Q我们将在下一文章讨义模块。现在,h意观察XML文g的结构。其中一个rule-set元素包含?
一个或多个rule元素Qrule元素又包含了parameterQcondition和consequence元素。Condition?
consequence元素包含的内容和Java很象。注意,在这些元素中Q有些事你可以做Q有些事你不能做。目前,Drools使用
BeanShell2.0b1作ؓ它的Java解释器。我在这里ƈ不想详细的讨论DRL文g和Java语义模块的语法。我们的目标是解释如何?
Drools的JSR94 API?br>
在Drools目CVS的drools-jsr94模块中,单元试代码包含了一个ExampleRuleEngineFacade对象Q它Z
Brian Topping的Dentaku目。这个fa?ade对象通过javax.rules
APIQ创Z供RuleExecutionSet和RuleSession使用的一pd对象。它q没有完全包括了Drools引擎API的所有特性和l?
微差别,但可以作为新手用API的一个简单例子?br> 下面的代码片断显C如何用规则引擎的facade构造一个RuleExecutionSet对象Qƈ通过它获得一个RuleSession对象?/div>
import java.io.InputStream; import javax.rules.*; import org.drools.jsr94.rules.ExampleRuleEngineFacade;
public class Example { private ExampleRuleEngineFacade engine; private StatelessRuleSession statelessSession;
/* place the rule file in the same package as this class */ private String bindUri = "myRuleFile.drl"
public Example() { /* get your engine facade */ engine = new ExampleRuleEngineFacade();
/* get your input stream */ InputStream inputStream = Example.class.getResourceAsStream(bindUri);
/* build a RuleExecutionSet to the engine */ engine.addRuleExecutionSet(bindUri, inputStream);
/* don't forget to close your InputStream! */ inputStream.close();
/* get your runtime session */ this.statelessSession = engine.getStatelessRuleSession(bindUri); } ... }
在以上的例子代码中,你需要处理InputStream的IOException例外Q这里ؓ了简单v见省略了。你要做的只是构建InputStream
对象Qƈ把它输入ExampleRuleEngineFacadeQ用来创Z个RuleExecutionSet对象。然后,你可以得C?
StatelessRuleSessionQƈ用它来执行所有的规则。用StatelessRuleSession相对单。我们可以给上面的类d一
个方法,用来对一个对象列表执行规则:
public List getUndervalued(List stocks) { return statelessSession.executeRules(stocks); }
该方法输入一个stock对象列表l规则引擎,然后使用规则评估输入的股对象,q剔除那些不W合价g估标准的股票。它是个单的例子Q但以说明问题?br>
在ExampleRuleEngineFacadecMQ代码会E微有些复杂。ExampleRuleEngineFacadecdZ一?
RuleServiceProvider对象Qƈ用它创徏RuleAdministratorQRuleExecutionSetProvider?
RuleRuntime对象。RuleExecutionSetProvider负责解释InputStreamQƈ创徏一?
RuleExecutionSet对象。RuleRuntime对象用来得到一个sessionQRuleAdministrator用来理所有的?
象。在往下是Drools核心APIQ它的核心是Rete法实现。我在这里不打算详细讨论Q但你可以看?
ExampleRuleEngineFacade的代码?br>
现在你已l看C在商业和U研斚w使用规则引擎的一些例子,q对Drools目有了基本的了解。在下一文章里Q我讨论DRL文g的结构和Java?
义模块,让你可以~写自己的DRL文g。还向你解释如何编写你自己的语义模块,讨论salience和working memory的概c?/div>
作?/strong>
N. Alex Rupp is a freelance software architect and developer
from Minneapolis, and the current JSR94 Lead for the Drools project.
]]>
[转]使用Drools 的项目引?/title> http://m.tkk7.com/ericwang/archive/2006/03/11/34783.htmlDion Dion Sat, 11 Mar 2006 01:59:00 GMT http://m.tkk7.com/ericwang/archive/2006/03/11/34783.html http://m.tkk7.com/ericwang/comments/34783.html http://m.tkk7.com/ericwang/archive/2006/03/11/34783.html#Feedback 0 http://m.tkk7.com/ericwang/comments/commentRss/34783.html http://m.tkk7.com/ericwang/services/trackbacks/34783.html 一般情况下, 只显式引?
drools-all-2.0.jar antlr-2.7.5.jar xercesImpl-2.6.2.jar
可以了.当然ClassPath下也要用一些其他的jar. 下蝲位置: http://dist.codehaus.org/drools/distributions/drools-2.0-bin-withdeps.zip
如果, 在DRL文g中定义了Java Function, q时候就要显式的引用:
q时? 引擎是需要janino把DRL中的java function描述转换成可执行的二q制代码(?)?
]]> [转]Drools and Mandarax http://m.tkk7.com/ericwang/archive/2006/03/11/34781.htmlDion Dion Sat, 11 Mar 2006 01:58:00 GMT http://m.tkk7.com/ericwang/archive/2006/03/11/34781.html http://m.tkk7.com/ericwang/comments/34781.html http://m.tkk7.com/ericwang/archive/2006/03/11/34781.html#Feedback 0 http://m.tkk7.com/ericwang/comments/commentRss/34781.html http://m.tkk7.com/ericwang/services/trackbacks/34781.html Drools and Mandarax 两个目做了两g不同的事? 一个是Forward Chaining,另一个是
backward chaining. Drools 是forward chaining? 意味着 它对assert的对象反?
事g驱动? Mandarax ?backward chaining? ?prologue一? 你问它问?
它试囄你它知道的答? 举例来说, 在用Drools的时? 你可能会先assert l它今天的日?
如果它发现有匚w的规则的?它会用事件的方式通知?今天是你的生?. ?backward chaining 的系l? 你可能先?
"今天是我的生日嘛?" pȝ会搜索它知道? 然后告诉你答? For an excellent explanation of forward and backward chaining read Charles Forgey's recent articles at http://rulespower.com/ - Forward and Backward Chaining: Parts 1, 2 and 3. ]]> [转]Open Source Rule Engines Written In Java http://m.tkk7.com/ericwang/archive/2006/03/11/34780.htmlDion Dion Sat, 11 Mar 2006 01:58:00 GMT http://m.tkk7.com/ericwang/archive/2006/03/11/34780.html http://m.tkk7.com/ericwang/comments/34780.html http://m.tkk7.com/ericwang/archive/2006/03/11/34780.html#Feedback 0 http://m.tkk7.com/ericwang/comments/commentRss/34780.html http://m.tkk7.com/ericwang/services/trackbacks/34780.html Open Source Rule Engines Written In Java
Drools
The drools engine uses a modified form of the Rete algorithm called the
Rete-OO algorithm. Internally it operates using the same concepts and
methods as Forgy's original but adds some node types required for
seemless integration with an object-oriented language. OFBiz Rule Engine Backward chaining is supported. Original code base from "Building Parsers in Java" by Steven John Metsker.
Mandarax
Based on backward reasoning. The easy integration of all kinds of data
sources. E.g., database records can be easily integrated as sets of
facts and reflection is used in order to integrate functionality
available in the object model. Algernon
Efficient and concise KB traversal and retrieval. Straightforward
access to ontology classes and instances. Supports both forward and
backward chaining. TyRuBa
TyRuBa supports higher order logic programming: variables and compound
terms are allowed everywhere in queries and rules, also in the position
of a functor- or predicate-name. TyRuBa speeds up execution by making
specialized copies of the rule-base for each query in the program. It
does so incrementally while executing a logic program and builds an
index for fast access to rules and facts in the rule base, tuned to the
program that is running. The indexing techniques works also for
higher-order logic. TyRuBa does 'tabling' of query results. JTP
Java Theorem Prover is based on a very simple and general reasoning
architecture. The modular character of the architecture makes it easy
to extend the system by adding new reasoning modules (reasoners), or by
customizing or rearranging existing ones. JEOPS
JEOPS adds forward chaining, first-order production rules to Java
through a set of classes designed to provide this language with some
kind of declarative programming. InfoSapient Semantics of business rules expressed using fuzzy logic.
JShop Simple Hierarchical Ordered Planner (SHOP) written in Java.
RDFExpert
RDF-driven expert system shell. The RDFExpert software uses Brian
McBride's JENA API and parser. A simple expert system shell that uses
RDF for all of its input: knowledge base, inference rules and elements
of the resolution strategy employed. It supports forward and backward
chaining. Jena 2
- Jena is a Java framework for writing Semantic Web applications. Jena2
has a reasoner subsystem which includes a generic rule based inference
engine together with configured rule sets for RDFS and for the OWL/Lite
subset of OWL Full. These reasoners can be used to construct inference
models which show the RDF statements entailed by the data being
reasoned over. The subsystem is designed to be extensible so that it
should be possible to plug a range of external reasoners into Jena,
though worked examples of doing so are left to a future release. JLisa
- JLisa is a powerful framework for building business rules accessible
to Java and it is compatible with JSR-94. JLisa is more powerful than
Clips because it has the expanded benefit of having all the features
from common lisp available. These features are essential for
multi-paradigm software development Euler
- Euler is a backward-chaining reasoner enhanced with Euler path
detection and will tell you whether a given set of facts and rules
supports a given conclusion. Things are described in N3. JLog
- JLog is an implementation of a Prolog interpreter, written in Java.
It includes built-in source editor, query panels, online help,
animation primitives, and a GUI debugger. Pellet OWL Reasoner
- Pellet is an open-source Java based OWL DL reasoner. It can be used
in conjunction with either Jena or OWL API libraries. Pellet API
provides functionalities to see the species validation, check
consistency of ontologies, classify the taxonomy, check entailments and
answer a subset of RDQL queries (known as ABox queries in DL
terminology). Pellet is an OWL DL reasoner based on the tableaux
algorithms developed for expressive Description Logics. Prova
- Prova is derived from Mandarax Java-based inference system developed
by Jens Dietrich. Prova extends Mandarax by providing a proper language
syntax, native syntax integration with Java, and agent messaging and
reaction rules. The development of this language was supported by the
grant provided within the EU project GeneStream. In the project, the
language is used as a rules-based backbone for distributed web
applications in biomedical data integration. ]]> 始终会用上的Common BeanUtils http://m.tkk7.com/ericwang/archive/2006/01/15/28118.htmlDion Dion Sun, 15 Jan 2006 12:20:00 GMT http://m.tkk7.com/ericwang/archive/2006/01/15/28118.html http://m.tkk7.com/ericwang/comments/28118.html http://m.tkk7.com/ericwang/archive/2006/01/15/28118.html#Feedback 2 http://m.tkk7.com/ericwang/comments/commentRss/28118.html http://m.tkk7.com/ericwang/services/trackbacks/28118.html
始终会用上的Common BeanUtils
Beanutils用了术般的反射技术,实现了很多夸张有用的功能Q都是C/C++时代不敢想的。无的项目,始终一天都会用得上它。我是后知后觉了,W一回看到它的时候居焉q?/p>
1.属性的动态getter、setter
在这框架满天飞的q代Q不能事事都保证执行getter,setter函数了,有时候属性是要根据名字动态取得的Q就像这P
BeanUtils.getProperty(myBean,"code"); 而Common BeanUtils的更强功能在于可以直接访问内嵌对象的属性,只要使用点号分隔?/div>
BeanUtils.getProperty(orderBean, "address.city"); 相比之下其他cd的BeanUtils通常都很单,不能讉K内嵌的对象,所以有时要用Commons BeanUtils来替换它们?br> BeanUtilsq支持List和Mapcd的属性,如下面的语法卛_取得Order的顾客列表中W一个顾客的名字
BeanUtils.getProperty(orderBean, "customers[1].name"); 其中BeanUtils会用ConvertUtilscL字符串{为Bean属性的真正cdQ方便从HttpServletRequest{对象中提取beanQ或者把bean输出到页面?/div>
而PropertyUtils׃原色的保留Bean原来的类型?/div>
2.BeanCompartor 动态排?
q是通过反射Q动态设定Bean按照哪个属性来排序Q而不再需要在实现bean的Compare接口q行复杂的条件判断?
List peoples = ...; // Person对象的列?br>Collections.sort(peoples, new BeanComparator("age")); 如果要支持多个属性的复合排序Q如"Order By lastName,firstName"
ArrayList sortFields = new ArrayList(); sortFields.add(new BeanComparator("lastName")); sortFields.add(new BeanComparator("firstName")); ComparatorChain multiSort = new ComparatorChain(sortFields); Collections.sort(rows,multiSort); 其中ComparatorChain属于jakata commons-collections包?br>如果age属性不是普通类型,构造函数需要再传入一个comparator对象为age变量排序?br>另外, BeanCompartor本n的ComparebleComparator, 遇到属性ؓnull׃抛出异常, 也不能设定升序还是降序。这个时候又要借助commons-collections包的ComparatorUtils.
Comparator mycmp = ComparableComparator.getInstance(); mycmp = ComparatorUtils.nullLowComparator(mycmp); //允许null mycmp = ComparatorUtils.reversedComparator(mycmp); //逆序 Comparator cmp = new BeanComparator(sortColumn, mycmp); 3.Converter 把Request或ResultSet中的字符串绑定到对象的属? l常要从request,resultSet{对象取出值来赋入bean中,如果不用MVC框架的绑定功能的话,下面的代码谁都写M?/p>
String a = request.getParameter("a"); bean.setA(a); String b = .... bean.setB(b); ...... 不妨写一个Binder自动l定所有属?
MyBean bean = ...; HashMap map = new HashMap(); Enumeration names = request.getParameterNames(); while (names.hasMoreElements()) { String name = (String) names.nextElement(); map.put(name, request.getParameterValues(name)); } BeanUtils.populate(bean, map); 其中BeanUtils的populateҎ或者getProperty,setPropertyҎ其实都会调用convertq行转换?br>
但Converter只支持一些基本的cdQ甚臌java.util.Datecd也不支持。而且它比较笨的一个地Ҏ当遇C认识的类型时Q居然会?
出异常来?nbsp;对于DatecdQ我参考它的sqldatecd实现了一个ConverterQ而且d了一个设|日期格式的函数?br>要把q个Converter注册Q需要如下语句:
ConvertUtilsBean convertUtils = new ConvertUtilsBean(); DateConverter dateConverter = new DateConverter(); convertUtils.register(dateConverter,Date.class); //因ؓ要注册converter,所以不能再使用BeanUtils的静态方法了Q必d建BeanUtilsBean实例 BeanUtilsBean beanUtils = new BeanUtilsBean(convertUtils,new PropertyUtilsBean()); beanUtils.setProperty(bean, name, value); 4 其他功能 4.1 ConstructorUtilsQ动态创建对?/strong>
public static Object invokeConstructor(Class klass, Object arg) 4.2 MethodUtilsQ动态调用方?/strong> MethodUtils.invokeMethod(bean, methodName, parameter); 4.3 PropertyUtilsQ当属性ؓCollection,Map时的动态读取: Collection: 提供index
BeanUtils.getIndexedProperty(orderBean,"items",1); 或?pre> BeanUtils.getIndexedProperty(orderBean,"items[1]");Map: 提供Key Value
BeanUtils.getMappedProperty(orderBean, "items","111");//key-value goods_no=111 或?pre> BeanUtils.getMappedProperty(orderBean, "items(111)")
4.4 PropertyUtilsQ直接获取属性的Classcd
public static Class getPropertyType(Object bean, String name) 4.5 动态Bean ?a target="__blank">用DynaBean减除不必要的VO和FormBean
]]>
Migrate apps from Internet Explorer to Mozilla http://m.tkk7.com/ericwang/archive/2006/01/04/26600.htmlDion Dion Wed, 04 Jan 2006 11:18:00 GMT http://m.tkk7.com/ericwang/archive/2006/01/04/26600.html http://m.tkk7.com/ericwang/comments/26600.html http://m.tkk7.com/ericwang/archive/2006/01/04/26600.html#Feedback 1 http://m.tkk7.com/ericwang/comments/commentRss/26600.html http://m.tkk7.com/ericwang/services/trackbacks/26600.html
Print this page
E-ma... 阅读全文 ]]> 【{载】Javascript的IE和Firefox兼容性汇~?/title> http://m.tkk7.com/ericwang/archive/2005/12/31/26203.htmlDion Dion Sat, 31 Dec 2005 09:55:00 GMT http://m.tkk7.com/ericwang/archive/2005/12/31/26203.html http://m.tkk7.com/ericwang/comments/26203.html http://m.tkk7.com/ericwang/archive/2005/12/31/26203.html#Feedback 1 http://m.tkk7.com/ericwang/comments/commentRss/26203.html http://m.tkk7.com/ericwang/services/trackbacks/26203.html 1. document.form.item 问题 (1)现有问题Q?br> 现有代码中存在许?document.formName.item("itemName") q样的语句,不能?MF 下运?br> (2)解决ҎQ?br> 改用 document.formName.elements["elementName"] (3)其它 参见 22. 集合cd象问?br> (1)现有问题Q?br> 现有代码中许多集合类对象取用时?()QIE 能接受,MF 不能?br> (2)解决ҎQ?br> 改用 [] 作ؓ下标q算。如Qdocument.forms("formName") 改ؓ document.forms["formName"]?br> 又如Qdocument.getElementsByName("inputName")(1) 改ؓ document.getElementsByName("inputName")[1] (3)其它
3. window.event (1)现有问题Q?br> 使用 window.event 无法?MF 上运?br> (2)解决ҎQ?br> MF ?event 只能在事件发生的现场使用Q此问题暂无法解冟뀂可以这样变通: 原代?可在IE中运?Q?br> <input type="button" name="someButton" value="提交" onclick="javascript:gotoSubmit()"/> ... <script language="javascript"> function gotoSubmit() { ... alert(window.event); // use window.event ... } </script>
C?可在IE和MF中运?Q?br> <input type="button" name="someButton" value="提交" onclick="javascript:gotoSubmit(event)"/> ... <script language="javascript"> function gotoSubmit(evt) { evt = evt ? evt : (window.event ? window.event : null); ... alert(evt); // use evt ... } </script> 此外Q如果新代码中第一行不改,与老代码一L??gotoSubmit 调用没有l参?Q则仍然只能在IE中运行,但不会出错。所以,q种Ҏ tpl 部分仍与老代码兼宏V?/p>
4. HTML 对象?id 作ؓ对象名的问题 (1)现有问题 ?IE 中,HTML 对象?ID 可以作ؓ document 的下属对象变量名直接使用。在 MF 中不能?br> (2)解决Ҏ ?getElementById("idName") 代替 idName 作ؓ对象变量使用?/p>
5. 用idName字符串取得对象的问题 (1)现有问题 在IE中,利用 eval(idName) 可以取得 id ?idName ?HTML 对象Q在MF 中不能?br> (2)解决Ҏ ?getElementById(idName) 代替 eval(idName)?/p>
6. 变量名与?HTML 对象 id 相同的问?br> (1)现有问题 ?MF 中,因ؓ对象 id 不作?HTML 对象的名Uͼ所以可以用与 HTML 对象 id 相同的变量名QIE 中不能?br> (2)解决Ҏ 在声明变量时Q一律加?var Q以避免歧义Q这样在 IE 中亦可正常运行?br> 此外Q最好不要取?HTML 对象 id 相同的变量名Q以减少错误?br> (3)其它 参见 问题4
7. event.x ?event.y 问题 (1)现有问题 在IE 中,event 对象?x, y 属性,MF中没有?br> (2)解决Ҏ 在MF中,与event.x {效的是 event.pageX。但event.pageX IE中没有?br> 故采?event.clientX 代替 event.x。在IE 中也有这个变量?br> event.clientX ?event.pageX 有微妙的差别Q当整个面有滚动条的时候)Q不q大多数时候是{效的?/p>
如果要完全一P可以E麻烦些Q?br> mX = event.x ? event.x : event.pageX; 然后?mX 代替 event.x (3)其它 event.layerX ?IE ?MF 中都有,具体意义有无差别未试验?/p>
8. 关于frame (1)现有问题 ?IE?可以用window.testFrame取得该frameQmf中不?br> (2)解决Ҏ 在frame的用方面mf和ie的最主要的区别是Q?br>如果在frame标签中书写了以下属性: <frame src="xx.htm" id="frameId" name="frameName" /> 那么ie可以通过id或者name讉Kq个frame对应的window对象 而mf只可以通过name来访问这个frame对应的window对象 例如如果上述frame标签写在最上层的window里面的htm里面Q那么可以这栯?br>ieQ?window.top.frameId或者window.top.frameName来访问这个window对象 mfQ?只能q样window.top.frameName来访问这个window对象
另外Q在mf和ie中都可以使用window.top.document.getElementById("frameId")来访问frame标签 q且可以通过window.top.document.getElementById("testFrame").src = 'xx.htm'来切换frame的内?br>也都可以通过window.top.frameName.location = 'xx.htm'来切换frame的内?br>关于frame和window的描q可以参见bbs的‘window与frame’文?br>以及/test/js/test_frame/目录下面的测?br>----adun 2004.12.09修改
9. 在mf中,自己定义的属性必getAttribute()取得 10.在mf中没?nbsp; parentElement parement.children 而用 parentNode parentNode.childNodes childNodes的下标的含义在IE和MF中不同,MF使用DOM规范QchildNodes中会插入I白文本节点?br> 一般可以通过node.getElementsByTagName()来回避这个问题?br> 当html中节点缺失时QIE和MF对parentNode的解释不同,例如 <form> <table> <input/> </table> </form> MF中input.parentNode的gؓform, 而IE中input.parentNode的gؓI?/p>
MF中节Ҏ有removeNodeҎQ必M用如下方?node.parentNode.removeChild(node)
11.const 问题 (1)现有问题: ?IE 中不能?const 关键字。如 const constVar = 32; 在IE中这是语法错误?br> (2)解决Ҏ: 不?const Q以 var 代替?/p>
12. body 对象 MF的body在body标签没有被浏览器完全d之前存在,而IE则必dbody完全被读入之后才存在
13. url encoding 在js中如果书写urlq接写&不要?amp;amp;例如var url = 'xx.jsp?objectName=xx&objectEvent=xxx'; frm.action = url那么很有可能url不会被正常显CZ至于参数没有正确的传到服务器 一般会服务器报错参数没有找?br>当然如果是在tpl中例外,因ؓtpl中符合xml规范Q要?amp;书写?amp;amp; 一般MF无法识别js中的&
14. nodeName ?tagName 问题 (1)现有问题Q?br> 在MF中,所有节点均?nodeName |?textNode 没有 tagName 倹{在 IE 中,nodeName 的用好?br> 有问题(具体情况没有试Q但我的IE已经M好几ơ)?br> (2)解决ҎQ?br> 使用 tagNameQ但应检其是否为空?/p>
15. 元素属?br> IE?input.type属性ؓ只读Q但是MF下可以修?/p> 16. document.getElementsByName() ?document.all[name] 的问?br> (1)现有问题Q?br> ?IE 中,getElementsByName()、document.all[name] 均不能用来取?div 元素Q是否还有其它不能取的元素还不知道)?img src ="http://m.tkk7.com/ericwang/aggbug/26203.html" width = "1" height = "1" />
]]>
վ֩ģ壺
ҹ˾ƷӰ߹ۿ
|
պһһ |
ĻƵ |
һ㽶 |
һƬѿ |
պƷ |
վ߹ۿ |
aɫëƬ |
δʮ˽˸ӰԺ |
Ʒ˾þ |
Ʒ˾þվ |
aëƬ߹ۿ |
Ʒһ |
츾AV߲ |
aëƬƵ |
㽶þþƷ
|
AVרߵӰ
|
ij˾þþþӰԺѹۿ
|
Ʒ
|
ѹۿ.WWW |
ŷպ |
ůůձ |
Ƶ |
ƷþþӰԺӰƬ
|
ƵƵ |
Ļ˾Ʒһվ |
ƷպһС˵ |
ҹ߲ |
߹ۿƵ |
Ů18ëƬˮ |
ůůձ |
AëƬվѿ |
337pձŷƷ555588
|
þþƷav٤ |
ľƷAVƬ |
߹ۿhƬ |
ѵĻɫҳѹۿ |
ۺ |
ëƬƵۿ |
һëƬѲһ |
Ʒֻ |