为什么我YY自己建的频道过了3个月还是没yy怎么取消接待频道?

信息提示
您的同一ip请求过于频繁,如果希望继续访问,请输入验证码:
Copyright 1998 – 2010 Tencent. All Rights Reserved.信息提示
您的同一ip请求过于频繁,如果希望继续访问,请输入验证码:
Copyright 1998 – 2010 Tencent. All Rights Reserved.常见问题--关注用户体验--歪歪***中心
***中心
帐号: 密码: 登录YY
YY帐号
YY密码 |
您所在的位置: > > 创 #24314;/删 #38500 #39057 #36947;
问题内容
为 #20160 #20040 #25105 #33258 #24049 #21019 #24314 #30340;YY频 #36947 #37117 #22909 #20960 #20010 #26376 #20102 #36824 #19981 #22238 #25910 #21602 #65292;
已 #22238 #22797;
提问时间:2010-09-22 10:22:19
问题编号:83900 | 提问者:ˊ #12289 #30494 #27442 #26395 #65110 #65318 #9474 #65326;.G1vEū 问题详细描述:我自己创建的频道,很早以前了,到现在也没回收,谁知道为什么阿。
YY官方答复
GM : G0430
2010-09-22 10:24:43
回复了该问题
尊敬的YY用户:
您好!很高兴为您服务!
关于您咨询的问题,很抱歉让您久等了! 目前是频道内三个月没有任何人进入您的频道,且频道积长增长少于1,系统回自动回收的,给您带来不便,请您谅解!
如仍有疑问欢迎您再次与我们联系,YY感谢您的支持并祝您使用愉快! O(&ca _&ca )O
以上信息是否已帮助你解决问题,请直接点击下列描述做出评价!
相关问题
2011-05-15 08:50:40
2011-05-15 08:49:42
2011-05-15 08:48:48
2011-05-15 08:47:42
2011-05-15 08:47:05
2011-05-15 08:46:32
2010-04-13 11:02:46
2010-04-12 11:10:06
2010-04-12 05:00:56
2010-04-10 10:05:27
2010-04-09 11:47:03
2011-08-03 09:50:33
2011-08-03 06:13:59
2011-08-02 08:57:41
2011-08-02 06:12:06
2011-08-02 05:35:30
2011-08-02 05:29:41
2011-08-02 05:27:06
2011-08-02 05:26:15
2011-08-02 05:26:15
< 上一页
| ******:020-
| ***频道:
广州华多网络科技有限公司 版权所有 2005-2010
DuoWan.com [多玩游戏] 写的非常好,拜读了!
--google
美神恶魔
--伊珊
str.trim()
--韩现龙未登录
--姜利阳
考验综合能力的时候
--姜利阳
2006年11月29日
为了使web应用能使用saas模式的大规模访问,必须实现应用的集群部署.要实现集群部署主要需要实现se ion共享机制,使得多台应用服务器之间会话统一, tomcat等多数服务都采用了se ion复制技术实现se ion的共享. se ion复制技术的问题: (1)技术复杂,必须在同一种中间件之间完成(如:tomcat-tomcat之间). (2)在节点持续增多的情况下,se ion复制带来的性能损失会快速增加.特别是当se ion中保存了较大的对象,而且对象变化较快时,性能下降更加显著.这种特性使得web应用的水平扩展受到了限制. se ion共享的另一种思路就是把se ion集中起来管理,首先想到的是采用数据库来集中存储se ion,但数据库是文件存储相对内存慢了一个数量级,同时这势必加大数据库系统的负担.所以需要一种既速度快又能远程集中存储的服务,所以就想到了memcached. memcached是什么? memcached是由Danga Interactive开发的,高性能的,分布式的内存对象缓存系统,用于在动态应用中减少数据库负载,提升访问速度。
memcached能缓存什么? 通过在内存里维护一个统一的巨大的hash表,Memcached能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。
memcached快么? 非常快。memcached使用了libevent(如果可以的话,在linux下使用epoll)来均衡任何数量的打开链接,使用非阻塞的网络I/O,对内部对象实现引用计数(因此,针对多样的客户端,对象可以处在多样的状态), 使用自己的页块分配器和哈希表, 因此虚拟内存不会产生碎片并且虚拟内存分配的时间复杂度可以保证为O(1).。
Danga Interactive为提升Danga Interactive的速度研发了memcached。目前,LiveJournal.com每天已经在向一百万用户提供多达两千万次的页面访问。而这些,是由一个由web服务器和数据库服务器组成的集群完成的。memcached几乎完全放弃了任何数据都从数据库读取的方式,同时,它还缩短了用户查看页面的速度、更好的资源分配方式,以及memcache失效时对数据库的访问速度。
memcached的特点 memcached的缓存是一种分布式的,可以让不同主机上的多个用户同时访问, 因此解决了共享内存只能单机应用的局限,更不会出现使用数据库做类似事情的时候,磁盘开销和阻塞的发生。 使用memcached来存储se ion有两种方案:
(1)直接通过tomcat6的扩展机制实现. 参考: http://www.javaeye.com/topic/81641
(2)通过自己编写filter实现.
考虑到系统的扩展,我们采用这种方案.这样可以使se ion共享机制和中间件脱钩. 参考: http://www.javaeye.com/topic/82565
主要思路:
(1)继承重构HttpServletRequestWra er,HttpSe ionWra er类,覆盖原来和se ion存取相关的方法呢,都通过Se ionService类来实现.
(2)使用filter拦截cookie中的se ionId,通过se ionId构造新的HttpServletRequestWra er对象,传给后面的应用.
(3)Se ionService连接memcached服务,以se ionId作为key,存取的对象是一个map.map的内容即为se ion的内容.
使用过程注意几个问题和改进思路:
1、memcache的内存应该足够大,这样不会出现用户se ion从Cache中被清除的问题(可以关闭memcached的对象退出机制)。
2、如果se ion的读取比写入要多很多,可以在memcache前再加一个Oscache等本地缓存,减少对memcache的读操作,从而减小网络开销,提高性能。
3、如果用户非常多,可以使用memcached组,通过set方法中带hashCode,插入到某个memcached服务器
对于se ion的清除有几种方案:
(1)可以在凌晨人最少的时候,对memcached做一次清空。(简单)
(2)保存在缓存中的对象设置一个失效时间,通过过滤器获取se ionId的值,定期刷新memcached中的对象.长时间没有被刷新的对象自动被清除.(相对复杂,消耗资源) posted @
鸿雁 阅读(173) |
| 提出问题:为啥要有双缓冲队列? 引用09年9月《程序员》上的一句话:双缓冲队列就是冲着同步/互斥的开销来的。我们知道,在多个线程并发访问同一个资源的时候,需要特别注意线程的同步问题。稍稍不注意,哦活,程序结果不正确了。最经典的就是“银行取钱”的例子,想想,都跟现金挂上钩了,看来这真不容忽视。 今天我们要谈的不是如何去给资源加锁解锁来解决同步问题,今天的重点在于,如何将线程同步的开销降低到我们力所能及的程度。如果你觉得,你可以通过增加硬件资源来弥补程序开销,那么,你将不可能成为一个优秀的程序员。 进入正题,先引入一个例子,两个实体:一个是玩具工厂,它的工作就是不停地生产玩具;另外一个实体就是小孩,它的工作就是不停地从工厂拿玩具。小孩不可能直接到工厂去“拿”玩具吧?呵呵,妈妈是绝对不会放心的。所以,我们有一个“搬运工”,搬运工自然要具备“存放”的功能,不然他怎么将玩具带给小孩呢,是吧。所以,我们先将搬运工定义为一个List,用来存放工厂生产出来的玩具。
代码如下
玩具类,定义一个玩具实体
public cla Toy { private String name; public String getName() { return name; }
public void setName(String name) { this.name = name; }
接下来是玩具工厂,它得“不停地”生产,所以,把它设计成一个线程类
玩具工厂,将玩具对象,放到list中
public cla Factory extends Thread{ public void run(){ while(true){ Toy t = new Toy (); t.setName("玩具"); synchronized (Tools.lT){ Tools.lT.add(t);
} try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } } } }
注意到,在上面这段代码当中,必须得用synchronized (Tools.lT)将Tools.lT给加锁。不然会出现线程同步问题(开销就在这里)。
再接下来,看看小孩是怎么“玩”玩具的:
小孩类,从list中取出玩具对象
public cla Kid extends Thread { long time1 = System.currentTimeMillis(); int count = 0; public void run() { while(true){ synchronized(Tools.lT){ if(Tools.lT.size()!=0) Tools.lT.remove(0); } count++; if(count==100000){ javax.swing.JOptionPane.showMe ageDialog(null, "用时间: "+(System.currentTimeMillis()-time1)); System.exit(0); } } }
当list不为空的时候,将list中的玩具对象,一个一个取出来,玩完!这个小孩可真够厉害的,呵呵。可以想象为,该类的工作就是不停地向list中取出玩具对象。OK,再来编写方法,如下
主方法
public cla MainTest { /** * @ aram args */ public static void main(String[] args) { Factory f = new Factory(); f.start(); Kid k = new Kid(); k.start(); }
最后是Tools类,他里面有个静态的List对象:
Tools类
public cla Tools { public static ListToylT = new ArrayListToy(10000);
这样,我们运行一下主方法,看看我们这位“天才”玩完100000个玩具,得花销多少的时间。 好,31毫秒。 这是我们的第一种解决方法,下面再来看第二种解决方法:
其实我们在Factory类和Kid类中都进行了同步处理,这样一来,浪费了很多时间,到底是不是这样的呢?我们可不可以直接用一个不用处理线程同步的容器来放Toy类对象呢?这样以来是不是就可以节省很多开销了?这个想法是有道理的,但是,事实是不是这样的呢?马上实践!
代码就不具体贴出来了,只是我们在Tools类中用到的是一个如下的对象
Public static LinkedBlockingQueueToy lT= new LinkedBlockingQueueToy(1000);
对,阻塞队列,这样我们就只管往里面取,从里面拿了,不用自己考虑同步问题,Factory类和Kid类中也不同特意去加关键字进行同步了。
那么这种方案的结果是多少呢?同样是100000个玩具,看结果 哦哦,变成16毫秒了,着实提高了不少效果呢。看来,在处理同步的时候挤时间,是有发展空间的,呵呵。
等等,有人要发话了,你在这磨叽了半天,还是没有说什么是双缓冲啊,对!有了前面的两种方案,我们再来看看“双缓冲队列”。
所谓双缓冲队列,自然起码要有两个队列吧,呵呵,在这个例子中,我们可以设计两个List来存放工厂生产出来的玩具对象。
下面分析一下:
两个List,一个用来存,一个用来取。有点迷糊?就是有一个listP从工厂那里得到玩具对象,另外一个listT就专门把它得到的玩具对象送去给 Kid类处理。当listT变成空的了以后,再将listP中在这段时间内取到的所有玩具对象放到listT中,好,这完了之后,他们两个就又各自干各自的去了:listP再去取,listT再去送。这样是不是就减少了很多次的线程同步呢?至少,在它们交换之前,listP是完全被工厂类线程占有,listT是完全被Kid类线程占有的,不用处理同步。只有在listT放完了,没得给了,再去跟ListP换过来,这个时候就要处理同步了。
跟实际联系一下,有两个搬运工A,B,A在工厂,专门从工厂取玩具;B在小孩子身边,专门送玩具给小孩玩。当B身上没有玩具了,自然要回A那里,把A身上的玩具全部拿过来,再来送给小孩玩。在A还有玩具的时候,A和B是在各自的线程里被处理的,即A在拿,B在给。不用担心同步问题。
这样以来,处理同步问题的次数是不是大大减少了呢?没错,就是这样的。那么怎么跟代码结合呢?
我们要设计一个监视线程,监视listP是不是空了,要是空了,把它同步起来,把listT也同步起来,让他们交换。完了就各自干各自的了。
我们来看看这个监视类:
public cla DoubleBufferList { private ListObject lP; private ListObject lT; private int ga /** * 构造方法 * * @ aram lP * 用来存放对象的队列 * @ aram lT * 用来取对象的队列 * @ aram gap * 交换的间隔 */ public DoubleBufferList(List lP, List lT, int gap) { this.lP = lP; this.lT = lT; this.gap = ga } public void check() { Ru able ru er = new Ru able() { public void run() { while (true) { if (lT.size() == 0) { synchronized (lT) { synchronized (lP) { lT.addAll(lP); } lP.clear(); } } try { Thread.sleep(gap); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Thread thread = new Thread(ru er); thread.start(); }
这个类中的线程方法就是用来交换的,目的就是为了减少处理同步的次数。这种方案中,Facotry类和Kid类跟前面单个List的情况差不多,就不再给出了。只是有一点要注意,Facory类中将玩具对象是放到了lP中,而Kid类中,也只是从lT中去取对象。看看Tools类中,多了一个变量:
Tools类,声明两个队列 public static ListToylT = new ArrayListToy(10000); public static ListToylP = new ArrayListToy(10000);
同样是让我们的“天才”玩完100000个玩具,来看看运行需要的时间: 哈哈,似乎跟我们上面的第二种方案,单阻塞队列,没有太大的差异。怎么解释呢?
不用着急,来,我将额定的玩具量后多加个“0”,让他玩完1000000个!改一下单阻塞队列方案的输出结果,给他们一个标记。再来看看结果: 效果出来了吧,我们再加大量,让他们同时处理10000000个玩具对象: 充分说明,使用双缓冲队列,比单缓冲阻塞队列的效果要好,更别说单缓冲队列了。
总结:
从上面的分析,我们可以得知,在处理线程同步的时候,是要花费我们的时间的,虽然在有些时候,这样的花费是我们可以接受的,但是在很多情况下,如果我们能注意到这样的浪费,并且及时地完善我们的程序,这样可以更大限度地提高我们程序的运行效率。尤其是在大的程序里面,这样的效果体现得更明显。而往往越大的系统,对性能的要求也就越高。
posted @
鸿雁 阅读(101) |
| android在处理一写图片资源的时候,会进行一些类型的转换,现在有空整理一下:
1、Drawable → Bitmap 的简单方法
((BitmapDrawable)res.getDrawable(R.drawable.youricon)).getBitmap();
2、Drawable → Bitmap
Java代码
public static Bitmap drawableToBitmap(Drawable drawable) { Bitmap bitmap = Bitma .createBitmap( drawable.getIntri icWidth(), drawable.getIntri icHeight(), drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565) Canvas canvas = new Canvas(bitmap) //canvas.setBitmap(bitmap) drawable.setBounds(0, 0, drawable.getIntri icWidth(), drawable.getIntri icHeight()) drawable.draw(canvas) return bitma } 3.Bitma #8594;Drawable 的简单方法
BitmapDrawable bitmapDrawable = (BitmapDrawable)bitma Drawable drawable = (Drawable)bitmapDrawable Bitmap bitmap = new Bitmap (...) Drawable drawable = new BitmapDrawable(bitmap) 3、从资源中获取Bitmap
Java代码
Resources res=getResources() Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.pic) 4、Bitmap → byte[]
Java代码
private byte[] Bitmap2Bytes(Bitmap bm){ ByteArrayOutputStream baos = new ByteArrayOutputStream() am bm.compre (Bitmap.Compre Format.PNG, 100, baos) am return baos.toByteArray() } 5、 byte[] → Bitmap
Java代码
private Bitmap Bytes2Bimap(byte[] b){ if(b.length!=0){ return BitmapFactory.decodeByteArray(b, 0, b.length) } else { return null } }
posted @
鸿雁 阅读(659) |
| 修改TabHost默认样式
TabHost是Android提供的一个容器组件,利用它可以轻松地实现TAB界面,如下图所示:
但很多时候,默认的TAB样式并不符合软件的整体风格,这时候该怎么办呢?其实,我们可以编写XML对其样式进行修改。下面修改后的效果图:
1. TabHost布局文件 main.xml
TabHost
android:id
"@+id/tabhost"
android:layout_width
"fill_parent"
android:layout_height
"fill_parent"
LinearLayout
android:orientation
"vertical"
android:layout_width
"fill_parent"
android:layout_height
"fill_parent"
TabWidget
android:id
"@android:id/ta "
android:layout_width
"fill_parent"
android:layout_height
"30dip"
android:background
"#a0a0a0"
android:layout_weight
FrameLayout
android:id
"@android:id/tabcontent"
android:layout_width
"fill_parent"
android:layout_height
"fill_parent"
android:layout_weight
ListView
android:id
"@+id/user_list"
android:layout_width
"fill_parent"
android:layout_height
"fill_parent"
android:divider
"@drawable/divider_line"
android:cacheColorHint
"#00000000"
ListView
android:id
"@+id/article_list"
android:layout_width
"fill_parent"
android:layout_height
"fill_parent"
android:divider
"@drawable/divider_line"
android:cacheColorHint
"#00000000"
ListView
android:id
"@+id/feed_list"
android:layout_width
"fill_parent"
android:layout_height
"fill_parent"
android:divider
"@drawable/divider_line"
android:cacheColorHint
"#00000000"
ListView
android:id
"@+id/book_list"
android:layout_width
"fill_parent"
android:layout_height
"fill_parent"
android:divider
"@drawable/divider_line"
android:cacheColorHint
"#00000000"
/FrameLayout
/LinearLayout
/TabHost
FrameLayout里有四个ListView 分别对应用户、文章、频道、图书。
TabWidget和FrameLayout的ID不能自己定义修改。
2. Activity后台代码
RelativeLayout articleTab
RelativeLayout
LayoutInflater.
inflate
minitab
TextView articleTabLabel
TextView
articleTab.
findViewById
tab_label
articleTabLabel.
setText
"文章"
; RelativeLayout feedTab
RelativeLayout
LayoutInflater.
inflate
minitab
TextView feedTabLabel
TextView
feedTab.
findViewById
tab_label
feedTabLabel.
setText
"频道"
; RelativeLayout bookTab
RelativeLayout
LayoutInflater.
inflate
minitab
TextView bookTabLabel
TextView
bookTab.
findViewById
tab_label
bookTabLabel.
setText
"图书"
; TabHost tabHost
TabHost
findViewById
tabhost
tabHost.
; tabHost.
tabHost.
newTabSpec
setIndicator
userTab
setContent
user_list
tabHost.
tabHost.
newTabSpec
"article"
setIndicator
articleTab
setContent
article_list
tabHost.
tabHost.
newTabSpec
setIndicator
feedTab
setContent
feed_list
tabHost.
tabHost.
newTabSpec
setIndicator
bookTab
setContent
book_list
TabHost创建出来以后,必须先setup一下,tabHost.setup();
setIndicator方法设置的View其实就对应了TAB中的一个个选项卡,它们都是通过一个叫minitab的布局文件inflate出来的
3. 选项卡布局文件minitab.xml
version
encoding
"utf-8"
RelativeLayout
xml :android
"http://schemas.android.com/apk/res/android"
android:layout_width
"fill_parent"
android:layout_height
"fill_parent"
android:paddingLeft
android:paddingRight
TextView
android:id
"@+id/tab_label"
android:layout_width
"fill_parent"
android:layout_height
"fill_parent"
android:gravity
"center"
android:textColor
"#000000"
android:textStyle
android:background
"@drawable/minitab"
/RelativeLayout
drawable/minitab是一个selector,指定了Tab选项卡的背景颜色。
4. selector文件 minitab.xml
version
encoding
"utf-8"
< elector
xml :android
"http://schemas.android.com/apk/res/android"
android:state_selected
"false"
android:drawable
"@drawable/minitab_u elected"
android:state_selected
android:drawable
"@drawable/minitab_default"
/selector
minitab_u elected是一浅蓝色背景图片
minitab_default是一白色背景图片
posted @
鸿雁 阅读(1234) |
| 摘 要 Java规则引擎是一种嵌入在Java程序中的组件,它的任务是把当前提交给引擎的Java数据对象与加载在引擎中的业务规则进行测试和比对,激活那些符合当前数据状态下的业务规则,根据业务规则中声明的执行逻辑,触发应用程序中对应的操作。
目前,Java社区推动并发展了一种引人注目的新技术——Java规则引擎(Rule Engine)。利用它就可以在应用系统中分离商业决策者的商业决策逻辑和应用开发者的技术决策,并把这些商业决策放在中心数据库或其他统一的地方,让它们能在运行时可以动态地管理和修改,从而为企业保持灵活性和竞争力提供有效的技术支持。
规则引擎的原理
1、基于规则的专家系统(RBES)简介
Java规则引擎起源于基于规则的专家系统,而基于规则的专家系统又是专家系统的其中一个分支。专家系统属于人工智能的范畴,它模仿人类的推理方式,使用试探性的方法进行推理,并使用人类能理解的术语解释和证明它的推理结论。为了更深入地了解Java规则引擎,下面简要地介绍基于规则的专家系统。RBES包括三部分:Rule Base(knowledge base)、Working Memory(fact base)和Inference Engine。它们的结构如下系统所示:
图1 基于规则的专家系统构成
如图1所示,推理引擎包括三部分:模式匹配器(Pattern Matcher)、议程(Agenda)和执行引擎(Execution Engine)。推理引擎通过决定哪些规则满足事实或目标,并授予规则优先级,满足事实或目标的规则被加入议程。模式匹配器决定选择执行哪个规则,何时执行规则;议程管理模式匹配器挑选出来的规则的执行次序;执行引擎负责执行规则和其他动作。
和人类的思维相对应,推理引擎存在两者推理方式:演绎法(Forward-Chaining)和归纳法(Backward-Chaining)。演绎法从一个初始的事实出发,不断地应用规则得出结论(或执行指定的动作)。而归纳法则是根据假设,不断地寻找符合假设的事实。Rete算法是目前效率最高的一个Forward-Chaining推理算法,许多Java规则引擎都是基于Rete算法来进行推理计算的。
推理引擎的推理步骤如下:
(1)将初始数据(fact)输入Working Memory。
(2)使用Pattern Matcher比较规则库(rule base)中的规则(rule)和数据(fact)。
(3)如果执行规则存在冲突(conflict),即同时激活了多个规则,将冲突的规则放入冲突集合。
(4)解决冲突,将激活的规则按顺序放入Agenda。
(5)使用执行引擎执行Agenda中的规则。重复步骤2至5,直到执行完毕所有Agenda中的规则。
上述即是规则引擎的原始架构,Java规则引擎就是从这一原始架构演变而来的。
2、规则引擎相关构件
规则引擎是一种根据规则中包含的指定过滤条件,判断其能否匹配运行时刻的实时条件来执行规则中所规定的动作的引擎。与规则引擎相关的有四个基本概念,为更好地理解规则引擎的工作原理,下面将对这些概念进行逐一介绍。
1)信息元(Information Unit)
信息元是规则引擎的基本建筑块,它是一个包含了特定事件的所有信息的对象。这些信息包括:消息、产生事件的应用程序标识、事件产生事件、信息元类型、相关规则集、通用方法、通用属性以及一些系统相关信息等等。
2)信息服务(Information Services)
信息服务产生信息元对象。每个信息服务产生它自己类型相对应的信息元对象。即特定信息服务根据信息元所产生每个信息元对象有相同的格式,但可以有不同的属性和规则集。需要注意的是,在一台机器上可以运行许多不同的信息服务,还可以运行同一信息服务的不同实例。但无论如何,每个信息服务只产生它自己类型相对应的信息元。
3)规则集(Rule Set)
顾名思义,规则集就是许多规则的集合。每条规则包含一个条件过滤器和多个动作。一个条件过滤器可以包含多个过滤条件。条件过滤器是多个布尔表达式的组合,其组合结果仍然是一个布尔类型的。在程序运行时,动作将会在条件过滤器值为真的情况下执行。除了一般的执行动作,还有三类比较特别的动作,它们分别是:放弃动作(Discard Action)、包含动作(Include Action)和使信息元对象内容持久化的动作。前两种动作类型的区别将在2.3规则引擎工作机制小节介绍。
4)队列管理器(Queue Manager)
队列管理器用来管理来自不同信息服务的信息元对象的队列。
下面将研究规则引擎的这些相关构件是如何协同工作的。
如图2所示,处理过程分为四个阶段进行:信息服务接受事件并将其转化为信息元,然后这些信息元被传给队列管理器,最后规则引擎接收这些信息元并应用它们自身携带的规则加以执行,直到队列管理器中不再有信息元。
图2 处理过程协作图
3、规则引擎的工作机制
下面专门研究规则引擎的内部处理过程。如图3所示,规则引擎从队列管理器中依次接收信息元,然后依规则的定义顺序检查信息元所带规则集中的规则。如图所示,规则引擎检查第一个规则并对其条件过滤器求值,如果值为假,所有与此规则相关的动作皆被忽略并继续执行下一条规则。如果第二条规则的过滤器值为真,所有与此规则相关的动作皆依定义顺序执行,执行完毕继续下一条规则。该信息元中的所有规则执行完毕后,信息元将被销毁,然后从队列管理器接收下一个信息元。在这个过程中并未考虑两个特殊动作:放弃动作(Discard Action)和包含动作(Include Action)。放弃动作如果被执行,将会跳过其所在信息元中接下来的所有规则,并销毁所在信息元,规则引擎继续接收队列管理器中的下一个信息元。包含动作其实就是动作中包含其它现存规则集的动作。包含动作如果被执行,规则引擎将暂停并进入被包含的规则集,执行完毕后,规则引擎还会返回原来暂停的地方继续执行。这一过程将递归进行。
图3 规则引擎工作机制
Java规则引擎的工作机制与上述规则引擎机制十分类似,只不过对上述概念进行了重新包装组合。Java规则引擎对提交给引擎的Java数据对象进行检索,根据这些对象的当前属性值和它们之间的关系,从加载到引擎的规则集中发现符合条件的规则,创建这些规则的执行实例。这些实例将在引擎接到执行指令时、依照某种优先序依次执行。一般来讲,Java规则引擎内部由下面几个部分构成:工作内存(Working Memory)即工作区,用于存放被引擎引用的数据对象集合;规则执行队列,用于存放被激活的规则执行实例;静态规则区,用于存放所有被加载的业务规则,这些规则将按照某种数据结构组织,当工作区中的数据发生改变后,引擎需要迅速根据工作区中的对象现状,调整规则执行队列中的规则执行实例。Java规则引擎的结构示意图如图4所示。
图4 Java规则引擎工作机制
当引擎执行时,会根据规则执行队列中的优先顺序逐条执行规则执行实例,由于规则的执行部分可能会改变工作区的数据对象,从而会使队列中的某些规则执行实例因为条件改变而失效,必须从队列中撤销,也可能会激活原来不满足条件的规则,生成新的规则执行实例进入队列。于是就产生了一种“动态”的规则执行链,形成规则的推理机制。这种规则的“链式”反应完全是由工作区中的数据驱动的。
任何一个规则引擎都需要很好地解决规则的推理机制和规则条件匹配的效率问题。规则条件匹配的效率决定了引擎的性能,引擎需要迅速测试工作区中的数据对象,从加载的规则集中发现符合条件的规则,生成规则执行实例。1982年美国卡耐基·梅隆大学的Charles L. Forgy发明了一种叫Rete算法,很好地解决了这方面的问题。目前世界顶尖的商用业务规则引擎产品基本上都使用Rete算法。
Java规则引擎API——JSR-94
为了使规则引擎技术标准化,Java社区制定了Java规则引擎API(JSR94)规范。它为Java平台访问规则引擎定义了一些简单的API。
Java规则引擎API在javax.rules包中定义,是访问规则引擎的标准企业级API。Java规则引擎API允许客户程序使用统一的方式和不同厂商的规则引擎产品交互,就如同使用JDBC编写独立于厂商访问不同的数据库产品一样。Java规则引擎API包括创建和管理规则集合的机制,在工作区中添加,删除和修改对象的机制,以及初始化,重置和执行规则引擎的机制。
1、Java规则引擎API体系结构
Java规则引擎API主要由两大类API组成: 规则管理API(The Rules Administrator API)和运行时客户API(The Runtime Client API)。
1)规则管理API
规则管理API在javax.rules.admin中定义,包含装载规则以及与规则对应的动作(执行集 execution sets)以及实例化规则引擎。规则可以从外部资源中装载,比如URI,I ut streams, XML streams和readers等等。同时规则管理API还提供了注册和取消注册执行集以及对执行集进行维护的机制。使用admin包定义规则有助于对客户访问运行规则进行控制管理,它通过在执行集上定义许可权使得未经授权的用户无法访问受控规则。
规则管理API使用类RuleServiceProvider来获得规则管理器(RuleAdministrator)接口的实例。该接口提供方法注册和取消注册执行集。规则管理器提供了本地和远程的RuleExecutionSetProvider,它负责创建规则执行集(RuleExecutionSet)。规则执行集可以从如XML streams, binary streams等来源中创建。这些数据来源及其内容经汇集和序列化后传送到远程的运行规则引擎的服务器上。在大多数应用程序中,远程规则引擎或远程规则数据来源的情况并不多。为了避免这些情况中的网络开销,API规定了可以从运行在同一JVM中规则库中读取数据的本地RuleExecutionSetProvider。规则执行集接口除了拥有能够获得有关规则执行集的方法,还有能够检索在规则执行集中定义的所有规则对象。这使得客户能够知道规则集中的规则对象并且按照自己需要来使用它们。
2)运行时客户API
运行时API在javax.rules包中定义,为规则引擎用户运行规则获得结果提供了类和方法。运行时客户只能访问那些使用规则管理API注册过的规则,运行时API帮助用户获得规则会话,并在这个会话中执行规则。
运行时API提供了对厂商规则引擎API的访问方法,这类似于JDBC。类RuleServiceProvider提供了对具体规则引擎实现的运行时和管理API的访问,规则引擎厂商通过该类将其规则引擎实现提供给客户,并获得RuleServiceProvider唯一标识规则引擎的URL。此URL的标准用法是使用类似于“com.mycompany.myrulesengine.rules.RuleServiceProvider”这样的Internet域名空间,这保证了访问URL的唯一性。类RuleServiceProvider内部实现了规则管理和运行时访问所需的接口。所有的RuleServiceProvider要想被客户所访问都必须用RuleServiceProviderManager进行注册,注册方式类似于JDBC API的DriverManager和Driver。
运行时接口是运行时API的关键部分。运行时接口提供了用于创建规则会话(RuleSe ion)的方法,规则会话是用来运行规则的。运行时API同时也提供了访问在service provider注册过的所有规则执行集(RuleExecutionSets)。规则会话接口定义了客户使用的会话的类型,客户根据自己运行规则的方式可以选择使用有状态会话或者无状态会话。无状态会话的工作方式就像一个无状态会话bean。客户可以发送单个输入对象或一列对象来获得输出对象。当客户需要一个与规则引擎间的专用会话时,有状态会话就很有用。输入的对象通过addObject() 方法可以加入到会话当中。同一个会话当中可以加入多个对象。对话中已有对象可以通过使用updateObject()方法得到更新。只要客户与规则引擎间的会话依然存在,会话中的对象就不会丢失。
RuleExecutionSetMetaData接口提供给客户让其查找规则执行集的元数据(metadata)。元数据通过规则会话接口(RuleSe ion Interface)提供给用户。
2、Java规则引擎API安全问题
规则引擎API将管理API和运行时API加以分开,从而为这些包提供了较好粒度的安全控制。规则引擎API并没有提供明显的安全机制,它可以和J2EE规范中定义的标准安全API联合使用。安全可以由以下机制提供,如Java 认证和授权服务 (JAAS),Java加密扩展(JCE),Java安***接字扩展(JSSE),或者其它定制的安全API。使用JAAS可以定义规则执行集的许可权限,从而只有授权用户才能访问。
3、异常与日志
规则引擎API定义了javax.rules.RuleException作为规则引擎异常层次的根类。所有其它异常都继承于这个根类。规则引擎中定义的异常都是受控制的异常(checked exceptio ),所以捕获异常的任务就交给了规则引擎。规则引擎API没有提供明确的日志机制,但是它建议将Java Logging API用于规则引擎API。
JSR 94 为规则引擎提供了公用标准API,仅仅为实现规则管理API和运行时API提供了指导规范,并没有提供规则和动作该如何定义以及该用什么语言定义规则,也没有为规则引擎如何读和评价规则提供技术性指导。
结束语
规则引擎技术为管理多变的业务逻辑提供了一种解决方案。规则引擎既可以管理应用层的业务逻辑又可以使表示层的页面流程可订制。这就给软件架构师设计大型信息系统提供了一项新的选择。而Java规则引擎在Java社区制定标准规范以后必将获得更大发展。
(1)下载ecli e(www.ecli e.org),如果是一般的java开发,下载Ecli e IDE for Java Developers就行了,解压后即可使用;
(2)下载Drools(http://jbo .org/drools/downloads.html),目前最新版本是Drools 4.0.7 Binaries,下载后解压即可;
(3)之后下载ecli e的Drools插件,版本跟ecli e对应,目前有Drools 4.0.7 Ecli e 3.2 Workbench和Drools 4.0.7 Ecli e Europa 3.3 Workbench两种。 Drools插件解压后,将里面的org.drools.ecli e_4.0.7.jar文件copy到ecli e的plugi 目录中,重启ecli e,在工具栏可以看到一个 图标,这就是Drools的工作台,之后就可通过这个按钮创建Drools resource文件了。
(4)开始Hello World
Java文件:DroolsTest.java
package com.sample;
import java.io.I utStreamReader;
import java.io.Reader;
import org.drools.RuleBase;
import org.drools.RuleBaseFactory;
import org.drools.WorkingMemory;
import org.drools.compiler.PackageBuilder;
import org.drools.rule.Package;
* This is a sample file to launch a rule package from a rule source file.
public cla DroolsTest { public static final void main(String[] args) { try { //load up the rulebase RuleBase ruleBase = readRule(); WorkingMemory workingMemory = ruleBase.newStatefulSe ion(); //go ! Me age me age = new Me age(); me age.setMe age( "Hello World" ); me age.setStatus( Me age.HELLO ); workingMemory.i ert( me age ); workingMemory.fireAllRules() } catch (Throwable t) { t.printStackTrace(); } } /** * Please note that this is the "low level" rule a embly API. */
private static RuleBase readRule() throws Exception { //read in the source Reader source = new I utStreamReader( DroolsTest.cla .getResourceAsStream( "/Sample.drl" ) ); //optionally read in the DSL (if you are using it). //Reader dsl = new I utStreamReader( DroolsTest.cla .getResourceAsStream( "/mylang.dsl" ) ); //Use package builder to build up a rule package. //An alternative lower level cla called "DrlParser" can also be used... PackageBuilder builder = new PackageBuilder(); //this wil parse and compile in one step //NOTE: There are 2 methods here, the one argument one is for normal DRL. builder.addPackageFromDrl( source ); //Use the following i tead of above if you are using a DSL: //builder.addPackageFromDrl( source, dsl ); //get the compiled package (which is serializable) Package pkg = builder.getPackage(); //add the package to a rulebase (deploy the rule package). RuleBase ruleBase = RuleBaseFactory.newRuleBase(); ruleBase.addPackage( pkg ); return ruleBase;
public static cla Me age { public static final int HELLO = 0; public static final int GOODBYE = 1; public static final int GAME_OVER = 2; private String me age; private int statu public String getMe age() { return this.me age; } public void setMe age(String me age) { this.me age = me age; } public int getStatus() { return this.statu } public void setStatus( int status ) { this.status = statu }
选择插件Drools按钮里的"New Rule resource",建立规则(rule)文件:Sample.drl
package com.sample
import com.sample.DroolsTest.Me age;
rule "Hello World"
when m : Me age( status == Me age.HELLO, me age : me age )
then System.out.println( me age ); m.setMe age( "Goodbye cruel world" ); m.setStatus( Me age.GOODBYE ); update( m );
rule "GoodBye"
no-loop true
when m : Me age( status == Me age.GOODBYE, me age : me age )
then System.out.println( me age ); m.setStatus(Me age.GAME_OVER); m.setMe age("game over now!"); update( m );
rule "game over"
when m : Me age( status == Me age.GAME_OVER)
then System.out.println( m.getMe age() ) end
注意:文件要放在相应的包里,然后编译—执行,当时出现了错误,查找资料,还需要加载包,包括:
1 Drools 4.0.7目录下的drools-core-4.0.7.jar,drools-compiler-4.0.7.jar
2 Drools 4.0.7\lib目录下的antlr-runtime-3.0.jar,mvel-1.3.1-java1.4.jar
3以及ecli e\plugi 目录下的org.ecli e.jdt.core_3.2.3.v_686_R32x.jar(不同版本,包名会稍有不同)。
重新运行,应该就不会有错了。执行结果如下:
Hello World
Goodbye cruel world
game over now!
posted @
鸿雁 阅读(94) |
| 特殊字符转义 由于 We 应用程序需要联合使用到多种语言,每种语言都包含一些特殊的字符,对于动态语言或标签式的语言而言,如果需要动态构造语言的内容时,一个我们经常会碰到的问题就是特殊字符转义的问题。下面是 We 开发者最常面对需要转义的特殊字符类型: HTML 特殊字符; JavaScript 特殊字符; SQL 特殊字符; 如果不对这些特殊字符进行转义处理,则不但可能破坏文档结构,还可以引发潜在的安全问题。Spring 为 HTML 和 JavaScript 特殊字符提供了转义操作工具类,它们分别是 HtmlUtil 和 JavaScriptUtils。 HTML 特殊字符转义 HTML 中 lt;,,&am 等字符有特殊含义,它们是 HTML 语言的保留字,因此不能直接使用。使用这些个字符时,应使用它们的转义序列: &am :&am " :" < :< > :> 由于 HTML 网页本身就是一个文本型结构化文档,如果直接将这些包含了 HTML 特殊字符的内容输出到网页中,极有可能破坏整个 HTML 文档的结构。所以,一般情况下需要对动态数据进行转义处理,使用转义序列表示 HTML 特殊字符。下面的 JSP 网页将一些变量动态输出到 HTML 网页中: 清单 1
. 未进行 HTML 特殊字符转义处理网页 %@ age language=
"java" contentType=
"text/html charset=utf-8"
% %! String userName = "/tdtr/table"
; String addre = " \" type=\"button"
; % table order=
lt;tr lt;td姓名:/tdtd%=userName%/td> ① lt;/tr lt;tr lt;td年龄:/tdtd
/td lt;/tr /table lt;i ut value=
"%=addre %" type=
"text" /> ② 在 ① 和 ② 处,我们未经任何转义处理就直接将变量输出到 HTML 网页中,由于这些变量可能包含一些特殊的 HTML 的字符,它们将可能破坏整个 HTML 文档的结构。我们可以从以上 JSP 页面的一个具体输出中了解这一问题: table order=
lt;tr lt;td姓名:/tdtd/tdtr/table/td> ① 破坏了 lt;table> 的结构 lt;/tr lt;tr lt;td年龄:/tdtd
/td lt;/tr /table lt;i ut value=
" " type=
"button" type=
"text" /> ② 将本来是输入框组件偷梁换柱为按钮组件 融合动态数据后的 HTML 网页已经面目全非,首先 ① 处的 lt;table> 结构被包含 HTML 特殊字符的 userName 变量截断了,造成其后的 lt;table> 代码变成无效的内容;其次,② 处 lt;i ut> 被动态数据改换为按钮类型的组件(type=
"button"
)。为了避免这一问题,我们需要事先对可能破坏 HTML 文档结构的动态数据进行转义处理。Spring 为我们提供了一个简单适用的 HTML 特殊字符转义工具类,它就是 HtmlUtils。下面,我们通过一个简单的例子了解 HtmlUtil 的具体用法: 清单 2
. HtmpEscapeExample package com.baobaotao.escape; import org. ringframework.web.util.HtmlUtil public cla HtmpEscapeExample { public static void main(String[] args) { String ecialStr = "div id=\"testDiv\"test1;test2/div"
; String tr1 = HtmlUtils.htmlEscape( ecialStr) ①转换为HTML转义字符表示 System.out.println(str1); String tr2 = HtmlUtils.htmlEscapeDecimal( ecialStr) ②转换为数据转义表示 System.out.println(str2); String tr3 = HtmlUtils.htmlEscapeHex( ecialStr) ③转换为十六进制数据转义表示 System.out.println(str3); ④下面对转义后字符串进行反向操作 System.out.println(HtmlUtils.htmlUnescape(str1)); System.out.println(HtmlUtils.htmlUnescape(str2)); System.out.println(HtmlUtils.htmlUnescape(str3)); } } HTML 不但可以使用通用的转义序列表示 HTML 特殊字符,还可以使用以 # 为前缀的数字序列表示 HTML 特殊字符,它们在最终的显示效果上是一样的。HtmlUtil 提供了三个转义方法: 方法 说明 static String htmlEscape(String i ut) 将 HTML 特殊字符转义为 HTML 通用转义序列; static String htmlEscapeDecimal(String i ut) 将 HTML 特殊字符转义为带 # 的十进制数据转义序列; static String htmlEscapeHex(String i ut) 将 HTML 特殊字符转义为带 # 的十六进制数据转义序列; 此外,HtmlUtil 还提供了一个能够将经过转义内容还原的方法:htmlUnescape(String i ut),它可以还原以上三种转义序列的内容。运行以上代码,您将可以看到以下的输出: str1:div id=
"testDiv"
test1;test2/div str2:div id=
"testDiv"
test1;test2/div str3:div id=
"testDiv"
test1;test2/div div id=
"testDiv"
test1;test2/div div id=
"testDiv"
test1;test2/div div id=
"testDiv"
test1;test2/div 您只要使用 HtmlUtil 对代码 清单 1 的 userName 和 addre 进行转义处理,最终输出的 HTML 页面就不会遭受破坏了。 JavaScript 特殊字符转义 JavaScript 中也有一些需要特殊处理的字符,如果直接将它们嵌入 JavaScript 代码中,JavaScript 程序结构将会遭受破坏,甚至被嵌入一些恶意的程序。下面列出了需要转义的特殊 JavaScript 字符: ' :\' " :\" \ :\\ 走纸换页: \f 换行:\ 换栏符:\t 回车:\r 回退符:\ 我们通过一个具体例子演示动态变量是如何对 JavaScript 程序进行破坏的。假设我们有一个 JavaScript 数组变量,其元素值通过一个 Java List 对象提供,下面是完成这一操作的 JSP 代码片断: 清单 3
. jsTest.j :未对 JavaScript 特殊字符进行处理 %@ age language=
"java" contentType=
"text/html charset=utf-8"
% j :directive.page import
"java.util.*"
/ % List textList = new ArrayList(); textList.add(
"\";alert();j=\""
); % < cript var txtList = new Array(); lt;% for ( int i = 0 i lt textList.size() i++) { % txtList[%=i%] = "%=textList.get(i)%" ① 未对可能包含特殊 JavaScript 字符的变量进行处理 lt;% } % /script 当客户端调用这个 JSP 页面后,将得到以下的 HTML 输出页面: < cript var txtList = new Array(); txtList[
;alert();j=
"" ① 本来是希望接受一个字符串,结果被植入了一段JavaScript代码 /script 由于包含 JavaScript 特殊字符的 Java 变量直接合并到 JavaScript 代码中,我们本来期望 ① 处所示部分是一个普通的字符串,但结果变成了一段 JavaScript 代码,网页将弹出一个 alert 窗口。想像一下如果粗体部分的字符串是“
";while(true)alert();j="
”时会产生什么后果呢? 因此,如果网页中的 JavaScript 代码需要通过拼接 Java 变量动态产生时,一般需要对变量的内容进行转义处理,可以通过 Spring 的 JavaScriptUtil 完成这件工作。下面,我们使用 JavaScriptUtil 对以上代码进行改造: %@ age language=
"java" contentType=
"text/html charset=utf-8"
% j :directive.page import
"java.util.*"
/ j :directive.page impyy自己建的频道都4个月了怎么还没消失
悬赏分:0
解决时间:2010-4-28 22:26
提问者:
yy自己建的频道都4个月了怎么还没消失,不是三个月不进那个YY就会自动删除吗
最佳***
官方不会删除不上的频道.. 10频道说可以 但是事实是不可以的,YY 我几年前申请了300多个号 每个号申请了3个频道. 现在挨个去看 没有一个消失的. 官方是在骗人.
分享给你的朋友吧:
对我有帮助
回答时间:2010-4-28 03:55
回答者:
擅长领域:
参加的活动:
暂时没有参加的活动
相关内容
2011-4-4
2011-5-15
2011-4-3
2011-7-6
2011-7-16
查看同主题问题:
其他回答
看看我的吧
YY频道ID:60550
回答者:
2010-4-26 15:19
分享到:
用户名:
记住我的登录状态
2011 Baidu

参考资料

 

随机推荐