首页 > 技术文章 > 利用SPI机制实现责任链模式中的处理类热插拔

wkynf 2020-12-03 00:58 原文

  最近看到责任链模式的时候每增加一个处理类,就必须在责任链的实现类中手动增加到责任链中,具体代码基本就是list.add(new FilterImpl()),可以看到每次增加一个处理类,就必须添加一行上面的代码,不符合开闭原则(面向修改关闭,面向扩展开放)。于是想到了Java的SPI机制,可以实现插拔式组件,而Java自带的SPI机制是寻找借口的所有实现类,虽然一直被诟病,但是在本次的插拔式中,它却成了一个优点,因为我们需要把所有的实现类都放入处理器链中。

类图如下:

 

 

上代码,嘻嘻!

 1 package com.liekkas.spi.responsibility_chain_model;
 2 
 3 import lombok.Data;
 4 
 5 /**
 6  * description 被处理的类
 7  *
 8  * @author liekkas 2020/12/02 23:33
 9  */
10 @Data
11 public class Receipt {
12     public Receipt(String code,String message){
13         this.code = code;
14         this.message = message;
15     }
16     private String code;
17     private String message;
18 }
 1 package com.liekkas.spi.responsibility_chain_model;
 2 
 3 /**
 4  * description 处理器接口
 5  *
 6  * @author liekkas 2020/12/02 23:30
 7  */
 8 public interface Filter {
 9 
10     /**
11      * 处理方法
12      * @param receipt receipt
13      * @param filterChain filterChain
14      */
15     void handle(Receipt receipt,FilterChain filterChain);
16 }
 1 package com.liekkas.spi.responsibility_chain_model;
 2 
 3 /**
 4  * description 处理器链接口
 5  *
 6  * @author liekkas 2020/12/02 23:31
 7  */
 8 public interface FilterChain {
 9 
10     /**
11      * 处理方法
12      * @param receipt receipt
13      */
14     void handleReceipt(Receipt receipt);
15 }
 1 package com.liekkas.spi.responsibility_chain_model.impl;
 2 
 3 import com.liekkas.spi.responsibility_chain_model.Filter;
 4 import com.liekkas.spi.responsibility_chain_model.FilterChain;
 5 import com.liekkas.spi.responsibility_chain_model.Receipt;
 6 
 7 /**
 8  * description 具体的处理器1
 9  *
10  * @author liekkas 2020/12/02 23:35
11  */
12 public class FilterImpl1 implements Filter {
13 
14     @Override
15     public void handle(Receipt receipt, FilterChain filterChain) {
16         if ("test001".equals(receipt.getCode())) {
17             System.out.println("我是Filter1,我能处理test001,已经处理" + receipt.getMessage());
18         }
19         //自己处理不了该回执就往下传递
20         else {
21             filterChain.handleReceipt(receipt);
22         }
23     }
24 }
 1 package com.liekkas.spi.responsibility_chain_model.impl;
 2 
 3 import com.liekkas.spi.responsibility_chain_model.Filter;
 4 import com.liekkas.spi.responsibility_chain_model.FilterChain;
 5 import com.liekkas.spi.responsibility_chain_model.Receipt;
 6 
 7 /**
 8  * description 具体的处理器2
 9  *
10  * @author liekkas 2020/12/02 23:35
11  */
12 public class FilterImpl2 implements Filter {
13 
14     @Override
15     public void handle(Receipt receipt, FilterChain filterChain) {
16         if ("test002".equals(receipt.getCode())) {
17             System.out.println("我是Filter2,我能处理test002,已经处理" + receipt.getMessage());
18         }
19         //自己处理不了该回执就往下传递
20         else {
21             filterChain.handleReceipt(receipt);
22         }
23     }
24 }
 1 package com.liekkas.spi.responsibility_chain_model.impl;
 2 
 3 import com.liekkas.spi.responsibility_chain_model.Filter;
 4 import com.liekkas.spi.responsibility_chain_model.FilterChain;
 5 import com.liekkas.spi.responsibility_chain_model.Receipt;
 6 
 7 /**
 8  * description 具体的处理器3
 9  *
10  * @author liekkas 2020/12/02 23:35
11  */
12 public class FilterImpl3 implements Filter {
13 
14     @Override
15     public void handle(Receipt receipt, FilterChain filterChain) {
16         if ("test003".equals(receipt.getCode())) {
17             System.out.println("我是Filter3,我能处理test003,已经处理" + receipt.getMessage());
18         }
19         //自己处理不了该回执就往下传递
20         else {
21             filterChain.handleReceipt(receipt);
22         }
23     }
24 }
 1 package com.liekkas.spi.responsibility_chain_model.impl;
 2 
 3 import com.liekkas.spi.responsibility_chain_model.Filter;
 4 import com.liekkas.spi.responsibility_chain_model.FilterChain;
 5 import com.liekkas.spi.responsibility_chain_model.Receipt;
 6 import com.liekkas.spi.responsibility_chain_model.container.ReceiptHandlerContainer;
 7 
 8 import java.util.List;
 9 
10 /**
11  * description 处理器链默认的实现类
12  *
13  * @author liekkas 2020/12/02 23:38
14  */
15 public class DefaultFilterChainImpl implements FilterChain {
16 
17     /**
18      * 记录当前处理者位置
19      */
20     private int index = 0;
21     /**
22      * 处理器集合
23      */
24     private static final List<Filter> FILTER_LIST;
25 
26     static {
27         //从容器中获取处理器对象
28         FILTER_LIST = ReceiptHandlerContainer.getReceiptHandlerList();
29     }
30 
31     @Override
32     public void handleReceipt(Receipt receipt) {
33         if (FILTER_LIST != null && FILTER_LIST.size() > 0) {
34             if (index < FILTER_LIST.size()) {
35                 Filter filter = FILTER_LIST.get(index++);
36                 filter.handle(receipt, this);
37             }
38         }
39     }
40 }
 1 package com.liekkas.spi.responsibility_chain_model.container;
 2 
 3 import com.liekkas.spi.responsibility_chain_model.Filter;
 4 
 5 import java.util.ArrayList;
 6 import java.util.List;
 7 import java.util.ServiceLoader;
 8 
 9 /**
10  * description 装在过滤器的容器,采用SPI实现,当添加过滤器的时候只需按照SPI的格式要求,便可自动装载,
11  * 无需其他操作,即实现了插拔式,即插即用。
12  *
13  * @author liekkas 2020/12/02 23:43
14  */
15 public class ReceiptHandlerContainer {
16     private ReceiptHandlerContainer() {
17     }
18 
19     public static List<Filter> getReceiptHandlerList() {
20         // SPI机制,寻找所有的实现类
21         ServiceLoader<Filter> filtersImplements = ServiceLoader.load(Filter.class);
22         List<Filter> receiptHandlerList = new ArrayList<>();
23         //把找到的所有的Filter的实现类放入List中
24         for (Filter filtersImplement : filtersImplements) {
25             receiptHandlerList.add(filtersImplement);
26         }
27         return receiptHandlerList;
28     }
29 }

最后在resources目录下建一个文件名为com.liekkas.spi.responsibility_chain_model.Filter的文件,文件名即是接口的全限定接口名,完整的目录如下:

src/main/resources/META-INF/services/com.liekkas.spi.responsibility_chain_model.Filter

 文件内容为:

com.liekkas.spi.responsibility_chain_model.impl.FilterImpl1
com.liekkas.spi.responsibility_chain_model.impl.FilterImpl2
com.liekkas.spi.responsibility_chain_model.impl.FilterImpl3

下面我们就建一个客户端的测试类,来看一下效果,激动人心的时刻到了,嘿嘿嘿

package com.liekkas.spi.responsibility_chain_model;

import com.liekkas.spi.responsibility_chain_model.impl.DefaultFilterChainImpl;

import java.util.ArrayList;
import java.util.List;

/**
 * description 测试客户端
 *
 * @author liekkas 2020/12/02 23:52
 */
public class Client {
    public static void main(String[] args) {
        //模拟回执
        List<Receipt> receiptList = ReceiptBuilder.generateReceiptList();

        for (Receipt receipt : receiptList) {
            //回执处理链对象
            FilterChain receiptHandleChain = new DefaultFilterChainImpl();
            receiptHandleChain.handleReceipt(receipt);
        }
    }

    static class ReceiptBuilder{
        public static List<Receipt> generateReceiptList(){
            List<Receipt> resultList = new ArrayList<>();
            resultList.add(new Receipt("test001","测试消息one"));
            resultList.add(new Receipt("test002","测试消息two"));
            resultList.add(new Receipt("test003","测试消息three"));
            return resultList;
        }
    }
}

执行的结果如下:

 

 小结:通过本次的学习,不仅对责任链模式有了更深的理解也对SPI机制有了更深的理解,同时两者的结合实现了插拔式,也让我对软件的设计原则有了更深一步的认识!

推荐阅读