Tiny之RuleEngine

规则引擎适合于做业务规则频繁变化的场景,我们的业务在应用过程中,也经常要处理大量的业务规则,当然,也希望能有一套规则引擎来支撑,这样是再好不过的。

对一些常用的商业规则引擎做一下了解,感觉非常不错,但是太贵了。看一些开源的引擎吧,也不错,但是感觉相对于我们自己这么简单的需求,太复杂了。

于是就想着自己做个,试试看能不能解决了自己的这些简单的业务规则频繁变化的业务场景,嗯嗯,脑子里大概过了一下电影,感觉路是通的,主要有如下业务需求:

  • 业务规则执行器需要支持多种,也应该支持业务人员自行扩展,原因是我自己设计的业务规则再完美,也不可能完美的适应所有人的胃口,所以这个默认可以有支持的,但是一定是可以扩展的
  • 业务规则要支持优先级,也就是说有的业务规则先执行,有的业务规则后执行
  • 业务规则允许排他规则,也就是说只要执行到排他规则,就可以马上结束
  • 业务规则可以允许重复执行,这样才可以方便的进行循环处理
  • 在规则引擎中,可以方便的使用Spring中的业务对象

于是就可以开始设计了:

规则执行器接口

由于业务规则执行器需要支持扩展,当然需要设计一个接口了:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

/**

 * 规则执行器,可以有多种实现

 */

public interface RuleExecutor<T extends Rule> {

    /**

     * 返回执行器类型

     *

     * @return

     */

    String getType();

 

    /**

     * 执行规则,并把结果放到上下文上

     *

     * @param context

     * @return 返回条件是否成立

     */

    boolean execute(Context context, T rule);

}

一共就两方法,getType用来返回规则执行器的类型,以确定它是解决哪种类型的规则的。

execute方法用来执行规则,执行的结果是一个布尔值,表示此条规则是否有执行。

规则引擎接口

接下来就是设计规则引擎的接口了:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

public interface RuleEngine {

    /**

     * 对指定上下文执行指定类型的规则

     *

     * @param context

     * @param ruleSetName

     */

    void execute(Context context, String ruleSetName);

 

    /**

     * 添加一组规则

     *

     * @param ruleSet

     */

    void addRules(RuleSet ruleSet);

 

    /**

     * 删除一组规则

     *

     * @param ruleSet

     */

    void removeRules(RuleSet ruleSet);

 

    /**

     * 添加规则执行器列表

     *

     * @param ruleExecutors

     */

    void addRuleExecutors(List<RuleExecutor> ruleExecutors);

 

    /**

     * 添加一个规则执行器

     *

     * @param ruleExecutor

     */

    void addRuleExecutor(RuleExecutor ruleExecutor);

     

    /**

     * 删除规则执行器列表

     *

     * @param ruleExecutors

     */

    void removeRuleExecutors(List<RuleExecutor> ruleExecutors);

 

    /**

     * 删除一个规则执行器

     *

     * @param ruleExecutor

     */

    void removeRuleExecutor(RuleExecutor ruleExecutor);

     

    /**

     * 设置一批规则执行器

     * @param ruleExecutors

     */

    void setRuleExecutors(List<RuleExecutor> ruleExecutors);

}

如上面的代码一样,还是非常简单的。

execute用来执行一个规则集,其它的方法就是对规则集和规则执行器的管理,只要看一遍就一清二楚了。

规则集对象

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

@XStreamAlias("rule-set")

public class RuleSet {

    /**

     * 同种名称的规则集会自动合并

     */

    @XStreamAsAttribute

    private String name;

     

    @XStreamImplicit

    private List<Rule> rules;

 

    public String getName() {

        return name;

    }

 

    public void setName(String name) {

        this.name = name;

    }

 

    public List<Rule> getRules() {

        if(rules==null){

            rules = new ArrayList<Rule>();

        }

        return rules;

    }

 

    public void setRules(List<Rule> rules) {

        this.rules = rules;

    }

}

规则集就两属性,一个属性是规则集的名称,另外一个属性就是一组规则。规则集的名称用来表示一组相关的业务规则。

规则抽象类

根据上面的业务需求,抽象类Rule的结构如下:

它里面只有基本的几个属性:优先级,标识,是否排他,是否允许重复,描述,标题,类型,有效性。

说好的业务规则呢,怎么描述?

由于不同的规则执行器,它可以支持的规则也不一样,因此这里的规则抽象类只有基本的一些属性,怎么样描述规则由其子类决定。

MVEL方式的规则及其执行器

Mvel规则

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

/**

 * 采用MVEL表达式作为条件实现

 * @author yancheng11334

 *

 */

@XStreamAlias("mvel-rule")

public class MvelRule extends Rule{

    //匹配条件

    private String condition;

    //后续操作

    private String action;

  

    public String getCondition() {

        return condition;

    }

 

    public void setCondition(String condition) {

        this.condition = condition;

    }

     

    public String getAction() {

        return action;

    }

 

    public void setAction(String action) {

        this.action = action;

    }

 

    public String getType(){

        return "mvel";

    }

 

    public String toString() {

        return "MvelRule [condition=" + condition + ", action=" + action

                + ", type=" + getType() + ", id=" + getId() + ", priority="+ getPriority() +", multipleTimes="+isMultipleTimes()+",exclusive="+isExclusive()+"]";

    }

 

    /**

     * 验证mvel规则的合法性

     */

    public boolean isVaild() {

        if(StringUtil.isEmpty(getCondition())){

            throw new RuntimeException(String.format("规则[%s]的匹配条件为空", getId()));

        }

        if(StringUtil.isEmpty(getAction())){

            throw new RuntimeException(String.format("规则[%s]的后续操作为空", getId()));

        }

        return true;

    }

}

上面表示,这个规则的类型都是mvel,这个规则包含了两个属性:condition和action,condition表示条件,只有条件执行结果为真的时候,才执行action中的处理。

Mvel规则执行器

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

public class MvelRuleExecutor implements RuleExecutor<MvelRule>{

 

    private EL el;

     

    public EL getEl() {

        return el;

    }

 

    public void setEl(EL el) {

        this.el = el;

    }

 

    public String getType() {

        return "mvel";

    }

 

    public boolean execute(Context context, MvelRule rule) {

        try{

            if(executeCondition(rule.getCondition(),context)){

                executeAction(rule.getAction(),context);

                return true;

            }else{

                return false;

            }

        }catch(RuntimeException e){

           throw e;

        }catch(Exception e){

           throw new RuntimeException("Mvel规则引擎执行器发生异常:",e);

        }

    }

     

    /**

     * 判断条件是否匹配

     * @param condition

     * @param context

     * @return

     */

    protected boolean executeCondition(String condition,Context context){

        try{

            MvelContext mvelContext=null;

            if(context instanceof MvelContext){

                mvelContext=(MvelContext) context;

            }else{

                mvelContext=new MvelContext(context);

            }

            return (Boolean)el.execute(condition, mvelContext);

        }catch(Exception e){

           throw new RuntimeException(String.format("条件[%s]匹配发生异常:", condition),e);

        }

    }

     

    /**

     * 执行条件匹配后的操作

     * @param action

     * @param context

     */

    protected void executeAction(String action,Context context) {

        try {

            MvelContext mvelContext = null;

            if (context instanceof MvelContext) {

                mvelContext = (MvelContext) context;

            } else {

                mvelContext = new MvelContext(context);

            }

 

            el.execute(action, mvelContext);

        } catch (Exception e) {

            throw new RuntimeException(String.format("后续操作[%s]执行发生异常:", action), e);

        }

    }

}

execute方法的意思是:如果执行条件表达式且返回真,那么就执行action中的处理,并返回true,否则就返回false。

呵呵,这个逻辑也太简单了。对,tiny框架的一大特点就是用非常简单的逻辑来实现相对复杂的处理。

Mvel上下文 

前面讲到,要方便的在表达式中调用Spring中托管的对象,这个的实现就要从上下文上作文章了:

?


1

2

3

4

5

6

7

8

9

10

public <T> T get(String name) {

        if(context.exist(name)){

           return (T)context.get(name);

        }else{

           //必须保存到上下文,否则每次返回不一定是同一个对象(scope可能是属性)

           T t = (T)beanContainer.getBean(name);

           context.put(name, t);

           return t;

        }

    }

主要的逻辑在上面,也就是说:如果上下文中有对像,那么就从上下文中取;如果没有,那么就从Spring容器中取。呵呵,这么高大上的功能,实现起来也这么简单。

规则引擎实现类

到上面为止,相关的准备工作都就绪了,规则引擎的实现类也可以现身了。其实这个类不贴吧,看文章的同学们一定说我藏着掖着,但是贴出来吧,真的没有啥技术含量:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

public class RuleEngineDefault implements RuleEngine {

    private Map<String, List<Rule>> ruleSetMap = new ConcurrentHashMap<String, List<Rule>>();

    private List<RuleExecutor> ruleExecutors = null;

    private Map<String, RuleExecutor> ruleExecutorMap = new ConcurrentHashMap<String, RuleExecutor>();

     

    protected static Logger logger = LoggerFactory

    .getLogger(RuleEngineDefault.class);

     

    public void execute(Context context, String ruleSetName) {

        List<Rule> ruleSet = ruleSetMap.get(ruleSetName);

        if (ruleSet != null) {

            Vector<Rule> newSet = new Vector<Rule>(ruleSet);

            processRuleSet(context, newSet);

        }

    }

 

    private void processRuleSet(Context context, Vector<Rule> newSet) {

        //如果没有后续规则,则退出

        if (newSet.size() == 0) {

            return;

        }

        Rule rule = newSet.get(0);

        RuleExecutor ruleExecutor = ruleExecutorMap.get(rule.getType());

        if (ruleExecutor != null) {

            boolean executed = ruleExecutor.execute(context, rule);

            if (executed) {

                //如果

                if (rule.isExclusive()) {

                    //如果条件成立,则是独占条件,则直接返回

                    return;

                } else if (!rule.isMultipleTimes()) {

                    //如果不是可重复执行的规则,则删除之

                    newSet.remove(0);

                }

            } else {

                //如果不匹配,则删除之

                newSet.remove(0);

            }

        } else {

            throw new RuntimeException("找不到对应" + rule.getType() + "的执行器");

        }

        processRuleSet(context, newSet);

    }

 

    public void addRules(RuleSet ruleSet) {

        List<Rule> rules = ruleSetMap.get(ruleSet.getName());

        if (rules == null) {

            rules = new Vector<Rule>();

            ruleSetMap.put(ruleSet.getName(), rules);

        }

        //检查规则

        for(Rule rule:ruleSet.getRules()){

            if(rule.isVaild()){

                rules.add(rule);

            }else{

                logger.logMessage(LogLevel.ERROR, String.format("规则[%s]检查无效.", rule.getId()));

            }

            rule.isVaild();

        }

        Collections.sort(rules);

    }

     

 

    public void removeRules(RuleSet ruleSet) {

        List<Rule> rules = ruleSetMap.get(ruleSet.getName());

        if (rules != null) {

            rules.removeAll(ruleSet.getRules());

        }

    }

 

    public void setRuleExecutors(List<RuleExecutor> ruleExecutors) {

        this.ruleExecutors = ruleExecutors;

        for (RuleExecutor ruleExecutor : ruleExecutors) {

            ruleExecutorMap.put(ruleExecutor.getType(), ruleExecutor);

        }

    }

 

    public void addRuleExecutor(RuleExecutor ruleExecutor) {

        if (ruleExecutors == null) {

            ruleExecutors = new ArrayList<RuleExecutor>();

        }

        ruleExecutors.add(ruleExecutor);

        ruleExecutorMap.put(ruleExecutor.getType(), ruleExecutor);

    }

 

    public void addRuleExecutors(List<RuleExecutor> ruleExecutors) {

        if(ruleExecutors!=null){

           for(RuleExecutor ruleExecutor:ruleExecutors){

               addRuleExecutor(ruleExecutor);

           }

        }

    }

 

    public void removeRuleExecutors(List<RuleExecutor> ruleExecutors) {

        if(ruleExecutors!=null){

           for(RuleExecutor ruleExecutor:ruleExecutors){

               removeRuleExecutor(ruleExecutor);

           }

        }

    }

 

    public void removeRuleExecutor(RuleExecutor ruleExecutor) {

        if (ruleExecutors == null) {

            ruleExecutors = new ArrayList<RuleExecutor>();

        }

        ruleExecutors.remove(ruleExecutor);

        ruleExecutorMap.remove(ruleExecutor.getType());

    }

}

一大堆维护规则和规则执行器的代码就不讲了,关键的几个讲下:

?


1

2

3

4

5

6

7

public void execute(Context context, String ruleSetName) {

        List<Rule> ruleSet = ruleSetMap.get(ruleSetName);

        if (ruleSet != null) {

            Vector<Rule> newSet = new Vector<Rule>(ruleSet);

            processRuleSet(context, newSet);

        }

    }

查找规则集,如果能找到就执行规则集,否则啥也不干。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

private void processRuleSet(Context context, Vector<Rule> newSet) {

        //如果没有后续规则,则退出

        if (newSet.size() == 0) {

            return;

        }

        Rule rule = newSet.get(0);

        RuleExecutor ruleExecutor = ruleExecutorMap.get(rule.getType());

        if (ruleExecutor != null) {

            boolean executed = ruleExecutor.execute(context, rule);

            if (executed) {

                //如果

                if (rule.isExclusive()) {

                    //如果条件成立,则是独占条件,则直接返回

                    return;

                } else if (!rule.isMultipleTimes()) {

                    //如果不是可重复执行的规则,则删除之

                    newSet.remove(0);

                }

            } else {

                //如果不匹配,则删除之

                newSet.remove(0);

            }

        } else {

            throw new RuntimeException("找不到对应" + rule.getType() + "的执行器");

        }

        processRuleSet(context, newSet);

    }

执行规则集的逻辑是:

如果规则集合中没有规则了,表示规则集已经执行完毕,直接返回。否则获取优先级最高的规则,首先检查是否有对象的规则执行器,如果没有,则抛异常。如果有就开始执行。

如果执行返回true,说明此规则被成功执行,则判断其是否是排他规则,如果是,则返回;否则检查是否是可重复执行规则,如果是则返回继续执行,否则把此条规则删除,继续执行下一条规则。

示例

这里假定做一个计算个人所得税的规则实例

定义规则

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

<rule-set name="feerule" >

     <!-- 独占类条件(执行顺序交互不影响执行结果) -->

     <!--优先级,数值越小优先级越高,用户设置优先级必须大于0;如果没有设置,系统会随机分配一个优先级;同一个规则集不能出现两个相同优先级的规则-->

     <mvel-rule id="step1"  multipleTimes="false" exclusive="true">

        <condition><![CDATA[salary<=3500]]></condition>

        <action><![CDATA[fee=0]]></action>

     </mvel-rule>

     <mvel-rule id="step2"  multipleTimes="false" exclusive="true">

        <condition><![CDATA[salary>3500 && salary<=5000]]></condition>

        <action><![CDATA[fee=(salary-3500)*0.03]]></action>

     </mvel-rule>

     <mvel-rule id="step3"  multipleTimes="false" exclusive="true">

        <condition><![CDATA[salary>5000 && salary<=8000]]></condition>

        <action><![CDATA[fee=(salary-3500)*0.1-105]]></action>

     </mvel-rule>

     <mvel-rule id="step4"  multipleTimes="false" exclusive="true">

        <condition><![CDATA[salary>8000 && salary<=12500]]></condition>

        <action><![CDATA[fee=(salary-3500)*0.2-555]]></action>

     </mvel-rule>

     <mvel-rule id="step5" multipleTimes="false" exclusive="true">

        <condition><![CDATA[salary>12500 && salary<=38500]]></condition>

        <action><![CDATA[fee=(salary-3500)*0.25-1005]]></action>

     </mvel-rule>

     <mvel-rule id="step6"  multipleTimes="false" exclusive="true">

        <condition><![CDATA[salary>38500 && salary<=58500]]></condition>

        <action><![CDATA[fee=(salary-3500)*0.3-2755]]></action>

     </mvel-rule>

     <mvel-rule id="step7"  multipleTimes="false" exclusive="true">

        <condition><![CDATA[salary>58500 && salary<=83500]]></condition>

        <action><![CDATA[fee=(salary-3500)*0.35-5505]]></action>

     </mvel-rule>

     <mvel-rule id="step8"  multipleTimes="false" exclusive="true">

        <condition><![CDATA[salary>83500]]></condition>

        <action><![CDATA[fee=(salary-3500)*0.45-13505]]></action>

     </mvel-rule>

  </rule-set>

编写TestCase

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

public void testFeeRule(){

        Context context = new MvelContext();

        context.put("fee", 0.0);

         

        context.put("salary", 1000);

        ruleEngine.execute(context, "feerule");

        assertEquals(0, context.get("fee"));

         

        context.put("salary", 4000);

        ruleEngine.execute(context, "feerule");

        assertEquals(15.0, context.get("fee"));

         

        context.put("salary", 7000);

        ruleEngine.execute(context, "feerule");

        assertEquals(245.0, context.get("fee"));

         

        context.put("salary", 21000);

        ruleEngine.execute(context, "feerule");

        assertEquals(3370.0, context.get("fee"));

         

        context.put("salary", 40005);

        ruleEngine.execute(context, "feerule");

        assertEquals(8196.50, context.get("fee"));

         

        context.put("salary", 70005);

        ruleEngine.execute(context, "feerule");

        assertEquals(17771.75, context.get("fee"));

         

        context.put("salary", 100000);

        ruleEngine.execute(context, "feerule");

        assertEquals(29920.00, context.get("fee"));

    }

看到这里的时候,我唯一的想法是:啥时我才可以一个月缴3万块的税呀。

总结

呵呵,按照Tiny惯例,传上代码统计数据:

至此,一个简单的规则引擎就实现了,总共代码行数不包含注释为:462行。可以较好的适应各种简单的业务逻辑频繁变化的业务场景。

可以访问Tiny主站:www.tinygroup.org获取更多内容。

时间: 2024-08-23 21:57:16

Tiny之RuleEngine的相关文章

悠然乱弹:“最好的模板引擎”Beetl 剖析及与Tiny模板引擎对比

Beetl的环境搭建 输入命令 ? 1 git clone https://git.oschina.net/xiandafu/beetl2.0.git 不一会儿,输出了下面的内容 ? 1 2 3 4 5 6 7 Cloning into 'beetl2.0'... remote: Counting objects: 5807, done. remote: Compressing objects: 100% (2145/2145), done. remote: Total 5807 (delta

Tiny模板引擎(Velocity Plus)应用示例

把TinyTemplate当成是Velocity的升级版其实也是可以的,毕竟它的语法是基到Veloccity扩展而来的,兼容度在80%以上. 至于TinyTemplate的实例是怎样的,且看下面: 宏的可变参数 在Java中的可变参数使用起来非常方便,Tiny模板也对可变参有一定支持. ? 1 2 3 4 5 6 7 8 #macro hello() ParameterList: ${helloParameterList.size()}     #for(para:helloParameterL

Tiny快速入门之Web界面快速开发实践

本来想改改OSChina的界面,但是研究了一下,OSChina界面实在是高大上呀,不是做不出来,只是工作量比较大,因此还是做个简单的网站来展示一下用Tiny开发界面的过程,同时在展示过程的同时,会把相关的知识做一个充分的介绍 . 一.寻找网站模板 要做网站,不能没有模板,自己不会做网页设计,咋办?问谷歌找百度呗,找了一阵,看到下面这个模板不错,就它了. http://www.tooplate.com/zip_files/2042_the_block.zip 相仔细了解这篇文章的同学,建议把原板的

从应用示例来认识Tiny框架

呵呵,Tiny框架神龙见首不见尾已经许多时间了,里面只看到一些几个孤零零的子框架.今天就通过Tiny开发示例的方式来重点展示一下利用Tiny框架是如何开发的. HelloWorld 首先从这个神一样的示例写起. 服务开发: 方式1:注解方式 ? 1 2 3 4 5 6 7 8 9 10 11 12 @ServiceComponent() public class HelloWorldAnnotationService{     @ServiceMethod(serviceId = "sayHel

TINY框架FAQ汇集

问题:Tiny的贡献者有哪些? 创建及主要设计者:悠悠然然 主要参与人员:Atizose,ballackhui,nishihe,达达 其它贡献人员:dandy 问题:要学习Tiny框架要有什么前提条件? 必备条件: 首先会Java 掌握Maven 熟悉git 可选条件: 有oschina的注册帐号:可以与Tiny框架构建者沟通 有oschina的git注册帐号:便于创建Tiny框架的Fork,并提交给原作者 对悠悠然然加粉:享受果粉待遇,得到辅导及及时回复 加入Q群:可即时互动 问题:学习Tin

构建Tiny生态圈

生态圈 生态圈又称商业生态圈,指商业活动的各利益相关者通过共同建立一个价值平台.各个角色关注其所在的价值平台的整体特性,通过平台撬动其它参与者的能力,使这一系统能够创造价值,并从中分享利益. 一个好的架构,必须构建一个围绕平台的生态系统,或者流行的说法,叫生态圈.因为再好的系统,如果只是做输出,总是会有这样那样不足的地方,Spring提供了一个依赖注入,实际上就是创建了一个Bean的生态圈,所以Spring的应用推广效果就非常好:Maven构建了一个插件生态圈和资产生态圈,所以,通过插件生态圈,

Tiny框架启动过程日志

一个系统的日志,可以看到许多东东. 下面是Tiny框架的Web应用启动与停止过程 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72

Tiny开发框架PPT介绍

我有一个梦想,那就是那一个NB的开发框架,让使用它的企业成本下降,让使用它的软件工程师轻松快乐.有人问我,你觉得smart框架与Tiny相比怎么样?我的回答是:smart是一个非常棒的框架.有人把JFinal的特性贴出来问我,你觉得Tiny框架与JFinal比怎么样?我的回答是:JFinal是一个非常出色的框架.不同的框架有不同的目标定位,有不同的目标群体,只要是使有者觉得不错,那就是合适的,就是好的.也有人非让我把Tiny框架和其它开源框架比较到底差异在哪里?这个问题确实不太好回答,于是我回答

Tiny Shell使用说明书

Tiny Shell是一款轻量级的标准远程Shell工具,可以提供远程执行命令(包括:Rlogin,Telnet,Ssh等)和文件传输功能(上传.下载),支持单字节,完全支持pseudo-Terminal Pairs(pty/tty)等伪终端. 一,前言 随着互联网的发展,使用Unix/Linux系统的越来越多,而入侵一台Unix/Linux系统也不再是什么难事了.通常,在入侵成功之后,都会留一个或几个后门,以便再次进入;对于Unix/Linux系统,后门的种类比较多,初级的有修改".rhost