在業務開發中,對於同一類邏輯處理,一般都是都是歸類爲一組集合,類似於一條業務鏈來處理,流程如下:
舉個例子,在下單過程中,會對生成訂單進行很多條件判斷。通常,會定義一個校驗接口Validator定義生成訂單的條件判斷業務的抽象;在下單過程因爲有很多不同的條件判斷,所以,就會在下單的服務中,定義類似於一組的校驗業務,例如,定義集合List<Validator> validators。
如果,在鏈式業務處理過程中,對於不同的訂單會有校驗邏輯需要滿足條件才能判斷,這時如何進行過濾呢?如果在不同的下單場景需要動態的添加或者修改一些校驗條件,應該如何操作呢?有的業務有不同的優先級和先後順序,應該如何設計?下面以tomcat中Filter過濾器鏈,Netty的事件鏈式處理爲例,來介紹常見的鏈式設計。tomcat的filter過濾器鏈基於List集合,Netty的事件鏈表基於鏈表實現。
tomcat中Filter過濾器的實現
在tomcat中,對於Http請求通常會進行用戶身份的校驗,權限的驗證,日誌處理等等業務的攔截和過濾。模仿tomcat實現的僞代碼,定義Filter接口實現過濾業務的封裝,CompositeFilter定義一組的過濾邏輯處理集合,FilterChain決定每次執行的FIlter的選擇邏輯,每次執行時,從條件過濾組中篩選滿足條件的過濾器Filter進行。過濾器鏈執行流程的大致如下:
Filter,CompositeFilter,FilterChain僞代碼定義如下:
/**
* 過濾器
**/
public interface Filter {
/**
* 過濾
*/
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
}
/**
* 過濾器每次執行的篩選定義
**/
public interface FilterChain {
void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}
/**
* 過濾器集合定義,使用List集合進行封裝
**/
public class CompositeFilter implements Filter {
// 過濾器列表
private List<? extends Filter> filters = new ArrayList();
public CompositeFilter() {
}
public void setFilters(List<? extends Filter> filters) {
this.filters = new ArrayList(filters);
}
/**
* 過濾邏輯
**/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
(new CompositeFilter.VirtualFilterChain(chain, this.filters)).doFilter(request, response);
}
/**
* 內部類實現自定義的FilterChain,根據list集合的index,從0開始順序的選擇Filter進行處理
*/
private static class VirtualFilterChain implements FilterChain {
private final FilterChain originalChain;
private final List<? extends Filter> additionalFilters;
// 起始篩選的index
private int currentPosition = 0;
public VirtualFilterChain(FilterChain chain, List<? extends Filter> additionalFilters) {
this.originalChain = chain;
this.additionalFilters = additionalFilters;
}
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
if (this.currentPosition == this.additionalFilters.size()) {
this.originalChain.doFilter(request, response);
} else {
++this.currentPosition;
// 根據index從過濾器集合中選擇Filter
Filter nextFilter = (Filter)this.additionalFilters.get(this.currentPosition - 1);
nextFilter.doFilter(request, response, this);
}
}
}
}
Netty中事件過濾器鏈的處理
在基於Socket的網絡編程中,當Socket綁定接口時,連接或斷開,讀取或者寫入數據時,都會有不同的業務需要處理。例如,從Socket讀取數據,或者寫人數據時,通常會進行數據的編碼節碼,數據的業務處理。Netty是對網絡編程的封裝,定義了ChannelHandler實現對各種事件的觸發的時的業務邏輯,定義ChannelPipeline基於鏈表集合實現對所有的事件處理邏輯封裝,ChannelHandlerContext基於前後事件的綁定,實現了對於每次執行事件觸發時,事件的選擇邏輯。其執行流程如下:
ChannelPipeline的默認實現類是DefaultChannelPipeline 在添加具體的ChannelHandler實現類時,會把ChannelHandler封裝爲AbstractChannelHandlerContext ,通過AbstractChannelHandlerContext 指定ChannelHandler前後的關聯節點。ChannelHandler,ChannelPipeline,ChannelHandlerContext接口源碼如下:
/**
* 各類Socket事件的具體業務定義的父接口
*/
public interface ChannelHandler {
/**
* 新增handler
*/
void handlerAdded(ChannelHandlerContext ctx) throws Exception;
/**
*刪除handler
*/
void handlerRemoved(ChannelHandlerContext ctx) throws Exception;
/**
* 異常的處理
*/
@Deprecated
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
}
/**
* 基於鏈表實現AbstractChannelHandlerContext的封裝,基於頭部和尾部的數據數據添加,各類事件監聽的統一調用
*/
public class DefaultChannelPipeline implements ChannelPipeline {
/**
* 鏈表head與tail節點定義
*/
final AbstractChannelHandlerContext head;
final AbstractChannelHandlerContext tail;
/**
* 鏈表首部插入邏輯
*/
private void addFirst0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext nextCtx = head.next;
newCtx.prev = head;
newCtx.next = nextCtx;
head.next = newCtx;
nextCtx.prev = newCtx;
}
/**
* 鏈表首部插尾部入邏輯
*/
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception { }
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { }
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
onUnhandledInboundException(cause);
}
/**
* 讀取數據事件邏輯
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
onUnhandledInboundMessage(msg);
}
/**
* 寫入數據事件邏輯
*/
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
unsafe.write(msg, promise);
}
}
/**
* 鏈表事件篩選邏輯
*/
abstract class AbstractChannelHandlerContext extends DefaultAttributeMap
implements ChannelHandlerContext, ResourceLeakHint {
/**
* 讀取數據邏輯
*/
@Override
public ChannelHandlerContext fireChannelRead(final Object msg) {
invokeChannelRead(findContextInbound(), msg);
return this;
}
/**
* 選取next指定的AbstractChannelHandlerContext執行
*/
private AbstractChannelHandlerContext findContextInbound() {
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.next;
} while (!ctx.inbound);
return ctx;
}
}