Java 中責(zé)任鏈模式實(shí)現(xiàn)的三種方式
責(zé)任鏈模式
責(zé)任鏈模式的定義:使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接受者之間的耦合關(guān)系, 將這個(gè)對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求,直到有一個(gè)對(duì)象處理他為止。這里就不再過多的介紹什么是責(zé)任鏈模式,主要來說說java中如何編寫。主要從下面3個(gè)框架中的代碼中介紹。
- servlet中的filter
- dubbo中的filter
- mybatis中的plugin 這3個(gè)框架在實(shí)現(xiàn)責(zé)任鏈方式不盡相同。
servlet中的Filter
servlet中分別定義了一個(gè) Filter和FilterChain的接口,核心代碼如下:
public final class ApplicationFilterChain implements FilterChain {
private int pos = 0; //當(dāng)前執(zhí)行filter的offset
private int n; //當(dāng)前filter的數(shù)量
private ApplicationFilterConfig[] filters; //filter配置類,通過getFilter()方法獲取Filter
private Servlet servlet
@Override
public void doFilter(ServletRequest request, ServletResponse response) {
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
Filter filter = filterConfig.getFilter();
filter.doFilter(request, response, this);
} else {
// filter都處理完畢后,執(zhí)行servlet
servlet.service(request, response);
}
}
}
代碼還算簡(jiǎn)單,結(jié)構(gòu)也比較清晰,定義一個(gè)Chain,里面包含了Filter列表和servlet,達(dá)到在調(diào)用真正servlet之前進(jìn)行各種filter邏輯。

Dubbo中的Filter
Dubbo在創(chuàng)建Filter的時(shí)候是另外一個(gè)方法,通過把Filter封裝成 Invoker的匿名類,通過鏈表這樣的數(shù)據(jù)結(jié)構(gòu)來完成責(zé)任鏈,核心代碼如下:
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
//只獲取滿足條件的Filter
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (filters.size() > 0) {
for (int i = filters.size() - 1; i >= 0; i --) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
last = new Invoker<T>() {
...
public Result invoke(Invocation invocation) throws RpcException {
return filter.invoke(next, invocation);
}
...
};
}
}
return last;
}
Dubbo的責(zé)任鏈就沒有類似FilterChain這樣的類吧Filter和調(diào)用Invoker結(jié)合起來,而是通過創(chuàng)建一個(gè)鏈表,調(diào)用的時(shí)候我們只知道第一個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)包含了下一個(gè)調(diào)用的節(jié)點(diǎn)信息。 這里的雖然Invoker封裝Filter沒有顯示的指定next,但是通過java匿名類和final的機(jī)制達(dá)到同樣的效果。

Mybatis中的Plugin
Mybatis可以配置各種Plugin,無論是官方提供的還是自己定義的,Plugin和Filter類似,就在執(zhí)行Sql語(yǔ)句的時(shí)候做一些操作。Mybatis的責(zé)任鏈則是通過動(dòng)態(tài)代理的方式,使用Plugin代理實(shí)際的Executor類。(這里實(shí)際還使用了組合模式,因?yàn)镻lugin可以嵌套代理),核心代碼如下:
public class Plugin implements InvocationHandler{
private Object target;
private Interceptor interceptor;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (滿足代理?xiàng)l件) {
return interceptor.intercept(new Invocation(target, method, args));
}
return method.invoke(target, args);
}
//對(duì)傳入的對(duì)象進(jìn)行代理,可能是實(shí)際的Executor類,也可能是Plugin代理類
public static Object wrap(Object target, Interceptor interceptor) {
Class<?> type = target.getClass();
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
}
簡(jiǎn)單的示意圖如下:

總結(jié)
這里簡(jiǎn)單介紹了Servlet、Dubbo、Mybatis對(duì)責(zé)任鏈模式的不同實(shí)現(xiàn)手段,其中Servlet是相對(duì)比較清晰,又易于實(shí)現(xiàn)的方式,而Dubbo和Mybatis則適合在原有代碼基礎(chǔ)上,增加責(zé)任鏈模式代碼改動(dòng)量最小的。
以上所述是小編給大家介紹的Java 中責(zé)任鏈模式實(shí)現(xiàn)的三種方式,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- Java設(shè)計(jì)模式之責(zé)任鏈模式(Chain of Responsibility模式)介紹
- 詳解Java實(shí)現(xiàn)設(shè)計(jì)模式之責(zé)任鏈模式
- Java責(zé)任鏈模式詳解
- JAVA設(shè)計(jì)模式之責(zé)任鏈模式詳解
- Java設(shè)計(jì)模式之責(zé)任鏈模式簡(jiǎn)介
- java設(shè)計(jì)模式(實(shí)戰(zhàn))-責(zé)任鏈模式
- Java責(zé)任鏈模式定義與用法分析
- Java責(zé)任鏈設(shè)計(jì)模式
- Java實(shí)現(xiàn)設(shè)計(jì)模式之責(zé)任鏈模式
- Java責(zé)任鏈模式的實(shí)現(xiàn)方法詳解
相關(guān)文章
基于Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的單詞本Android App的實(shí)踐
本文基于Java實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的單詞本安卓app,用的是SQLite數(shù)據(jù)庫(kù),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
Java中隊(duì)列(Queue)和列表(List)的區(qū)別解析
Java中的列表(List)和隊(duì)列(Queue)是兩種常用的數(shù)據(jù)結(jié)構(gòu),它們分別用于不同的場(chǎng)景,列表是有序的,支持隨機(jī)訪問,允許重復(fù)元素,并且可以通過索引插入或刪除元素,下面通過本文給大家介紹Java中隊(duì)列(Queue)和列表(List)的區(qū)別,感興趣的朋友一起看看吧2025-03-03
Java中Map循環(huán)遍歷的五種方法實(shí)現(xiàn)
本文主要介紹了Java中Map循環(huán)遍歷的五種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
SpringBoot集成Redis使用Cache緩存的實(shí)現(xiàn)方法
SpringBoot通過配置RedisConfig類和使用Cache注解可以輕松集成Redis實(shí)現(xiàn)緩存,主要包括@EnableCaching開啟緩存,自定義key生成器,改變序列化規(guī)則,以及配置RedisCacheManager,本文為使用SpringBoot與Redis處理緩存提供了詳實(shí)的指導(dǎo)和示例,感興趣的朋友一起看看吧2024-10-10
Java利用PDFBox實(shí)現(xiàn)PDF文檔基本操作
這篇文章主要為大家詳細(xì)介紹了java如何利用PDFBox實(shí)現(xiàn)PDF文檔基本操作,例如創(chuàng)建PDF文檔、加載PDF文檔、獲取總頁(yè)數(shù)等,需要的小伙伴可以參考下2023-11-11
Springboot整合Dubbo教程之項(xiàng)目創(chuàng)建和環(huán)境搭建
本篇文章主要介紹了Springboot整合Dubbo教程之項(xiàng)目創(chuàng)建和環(huán)境搭建,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-12-12
java中ArrayList 、LinkList的區(qū)別分析
java中ArrayList 、LinkList的區(qū)別分析,需要的朋友可以參考一下2013-05-05
詳解Java中的checked異常和unchecked異常區(qū)別
這篇文章主要介紹了詳解Java中的checked異常和unchecked異常區(qū)別,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-02-02

