Java 中責(zé)任鏈模式實(shí)現(xiàn)的三種方式
責(zé)任鏈模式
責(zé)任鏈模式的定義:使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接受者之間的耦合關(guān)系, 將這個(gè)對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求,直到有一個(gè)對(duì)象處理他為止。這里就不再過(guò)多的介紹什么是責(zé)任鏈模式,主要來(lái)說(shuō)說(shuō)java中如何編寫(xiě)。主要從下面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配置類(lèi),通過(guò)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è)方法,通過(guò)把Filter封裝成 Invoker的匿名類(lèi),通過(guò)鏈表這樣的數(shù)據(jù)結(jié)構(gòu)來(lái)完成責(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é)任鏈就沒(méi)有類(lèi)似FilterChain這樣的類(lèi)吧Filter和調(diào)用Invoker結(jié)合起來(lái),而是通過(guò)創(chuàng)建一個(gè)鏈表,調(diào)用的時(shí)候我們只知道第一個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)包含了下一個(gè)調(diào)用的節(jié)點(diǎn)信息。 這里的雖然Invoker封裝Filter沒(méi)有顯示的指定next,但是通過(guò)java匿名類(lèi)和final的機(jī)制達(dá)到同樣的效果。
Mybatis中的Plugin
Mybatis可以配置各種Plugin,無(wú)論是官方提供的還是自己定義的,Plugin和Filter類(lèi)似,就在執(zhí)行Sql語(yǔ)句的時(shí)候做一些操作。Mybatis的責(zé)任鏈則是通過(guò)動(dòng)態(tài)代理的方式,使用Plugin代理實(shí)際的Executor類(lèi)。(這里實(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類(lèi),也可能是Plugin代理類(lèi) 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ì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- Java設(shè)計(jì)模式之責(zé)任鏈模式(Chain of Responsibility模式)介紹
- 實(shí)例講解Java的設(shè)計(jì)模式編程中責(zé)任鏈模式的運(yùn)用
- JAVA設(shè)計(jì)模式之責(zé)任鏈模式詳解
- Java經(jīng)典設(shè)計(jì)模式之責(zé)任鏈模式原理與用法詳解
- Java設(shè)計(jì)模式之責(zé)任鏈模式簡(jiǎn)介
- Java責(zé)任鏈模式定義與用法分析
- 輕松掌握java責(zé)任鏈模式
- Java設(shè)計(jì)模式編程中的責(zé)任鏈模式使用示例
- Java設(shè)計(jì)模式之責(zé)任鏈模式的概念、實(shí)現(xiàn)以及netty中的責(zé)任鏈模式
相關(guān)文章
Java線性結(jié)構(gòu)中棧、隊(duì)列和串的基本概念和特點(diǎn)詳解
前幾天小編給大家介紹了Java線性結(jié)構(gòu)中的鏈表,除了鏈表這種結(jié)構(gòu)之外,實(shí)際上還有棧、隊(duì)列、串等結(jié)構(gòu),那么這些結(jié)構(gòu)又有哪些特點(diǎn)呢,本文就給大家詳細(xì)的介紹一下,感興趣的小伙伴跟著小編一起來(lái)看看吧2023-07-07一個(gè)applicationContext 加載錯(cuò)誤導(dǎo)致的阻塞問(wèn)題及解決方法
這篇文章主要介紹了一個(gè)applicationContext 加載錯(cuò)誤導(dǎo)致的阻塞問(wèn)題及解決方法,需要的朋友可以參考下2018-11-11Spring Data Jpa 自動(dòng)生成表結(jié)構(gòu)的方法示例
這篇文章主要介紹了Spring Data Jpa 自動(dòng)生成表結(jié)構(gòu)的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04spring?boot?3使用?elasticsearch?提供搜索建議的實(shí)例詳解
這篇文章主要介紹了spring?boot3使用elasticsearch提供搜索建議,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08SpringBoot + thymeleaf 實(shí)現(xiàn)讀取視頻列表并播放視頻功能
這篇文章主要介紹了SpringBoot + thymeleaf 實(shí)現(xiàn)讀取視頻列表并播放視頻功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04Springboot重寫(xiě)addInterceptors()方法配置攔截器實(shí)例
這篇文章主要介紹了Springboot重寫(xiě)addInterceptors()方法配置攔截器實(shí)例,spring?boot拋棄了復(fù)雜的xml配置,我們可以自定義配置類(lèi)(標(biāo)注@Configuration注解的類(lèi))來(lái)實(shí)現(xiàn)WebMvcConfigurer接口,并重寫(xiě)addInterceptors()方法來(lái)配置攔截器,需要的朋友可以參考下2023-09-09詳解Java?redis中緩存穿透?緩存擊穿?雪崩三種現(xiàn)象以及解決方法
緩存穿透是指緩存和數(shù)據(jù)庫(kù)中都沒(méi)有的數(shù)據(jù),而用戶(hù)不斷發(fā)起請(qǐng)求,如發(fā)起為id為“-1”的數(shù)據(jù)或id為特別大不存在的數(shù)據(jù)。這時(shí)的用戶(hù)很可能是攻擊者,攻擊會(huì)導(dǎo)致數(shù)據(jù)庫(kù)壓力過(guò)大2022-01-01Spring Boot下如何自定義Repository中的DAO方法
這篇文章主要介紹了Spring Boot下如何自定義Repository中的DAO方法,需要的朋友可以參考下2017-06-06