利用SPI机制实现责任链模式中的处理类热插拔
最近看到责任链模式的时候每增加一个处理类,就必须在责任链的实现类中手动增加到责任链中,具体代码基本就是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机制有了更深的理解,同时两者的结合实现了插拔式,也让我对软件的设计原则有了更深一步的认识!