一分鐘教你實(shí)現(xiàn)攔截器架構(gòu)
攔截器主要用于攔截用戶請(qǐng)求并作相應(yīng)的處理.
例如, Spring MVC通過攔截器可以進(jìn)行權(quán)限驗(yàn)證、記錄日志等;
Mybatis通過插件實(shí)現(xiàn)分頁(yè)功能, 而這個(gè)插件就是攔截器.
架構(gòu)圖如下:

攔截器一般都是使用代理模式+責(zé)任鏈一起實(shí)現(xiàn)的, 下面一起看下這兩種設(shè)計(jì)模式.
一. 代理模式
代理模式給某一個(gè)對(duì)象提供一個(gè)代理對(duì)象, 并由代理對(duì)象控制對(duì)原對(duì)象的引用.
代理模式是非常常見一個(gè)設(shè)計(jì)模式, 一般分為動(dòng)態(tài)代理和靜態(tài)代理, 我們以動(dòng)態(tài)代理為例看下, 如何實(shí)現(xiàn)一套代理模式.
代理模式主要分為三部分: 接口, 實(shí)現(xiàn)類, 代理類.
接口:
public interface UserService {void addUser();}
實(shí)現(xiàn)類:
public class UserServiceImpl implements UserService {public UserServiceImpl() {}public void addUser() {System.out.println("this is addUser() method!");}}
代理類:
public class UserServiceInvocationHandler implements InvocationHandler {private Object targetObject;public UserServiceInvocationHandler(Object targetObject) {this.targetObject = targetObject;}public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("do something");Object result = method.invoke(targetObject, args);return result;}}
測(cè)試類:
private static void test1() {UserService targetObject = new UserServiceImpl();UserServiceInvocationHandler proxy = new UserServiceInvocationHandler(targetObject);UserService object = (UserService) Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), proxy);object.addUser();}
二.?責(zé)任鏈模式
為方便多個(gè)代理的擴(kuò)展, 還需要引入過責(zé)任鏈模式.
責(zé)任鏈模式是一種對(duì)象的行為模式. 在責(zé)任鏈模式里, 很多對(duì)象由包含下一個(gè)對(duì)象引用的對(duì)象而連接起來形成一條鏈. 請(qǐng)求在這個(gè)鏈上傳遞, 直到鏈上的某一個(gè)對(duì)象決定處理此請(qǐng)求.
責(zé)任鏈設(shè)計(jì)模式能夠根據(jù)配置, 自由組合, 動(dòng)態(tài)調(diào)用.
責(zé)任鏈模式實(shí)現(xiàn)代碼主要分為三部分: 責(zé)任鏈, 鏈節(jié)點(diǎn), 處理實(shí)體.
結(jié)合上面的代理模式, 實(shí)現(xiàn)代碼如下:
責(zé)任鏈:
public?class?InterceptorChain?{??private?final?List?interceptors?=?new?ArrayList (); public Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) {target = interceptor.plugin(target);}return target;??}public void addInterceptor(Interceptor interceptor) {interceptors.add(interceptor);??}public ListgetInterceptors() {return Collections.unmodifiableList(interceptors);??}}
鏈節(jié)點(diǎn):
public?interface?Interceptor?{??Object?intercept(Invocation?invocation)?throws?Throwable;??Object?plugin(Object?target);}public?class?LogInterceptor?implements?Interceptor?{public Object intercept(Invocation invocation) throws Throwable {System.out.println(Thread.currentThread().getName()+ "\tlog intercept..."+ invocation.toString());return invocation.proceed();????}public Object plugin(Object target) {return Plugin.wrap(target, this);}}
處理實(shí)體:
public interface UserService {void addUser();}public?class?UserServiceImpl?implements?UserService?{????public?UserServiceImpl()?{}public void addUser() {System.out.println("this is addUser() method!");????}}
測(cè)試類
private static void test2() {InterceptorChain chain = new InterceptorChain();chain.addInterceptor(new LogInterceptor());UserService service = new UserServiceImpl();UserService object = (UserService) chain.pluginAll(service);object.addUser();}
為適應(yīng)更多應(yīng)用場(chǎng)景, ?可以在invoke()方法前后分別抽象出perHandler()和postHandler()方法, 進(jìn)行更多擴(kuò)展.
注: 這里的類設(shè)計(jì)來源于mybatis的plugin模塊.
總結(jié)
萬(wàn)物之始, 大道至簡(jiǎn), 衍化至繁.
通過代理和責(zé)任鏈兩個(gè)非常簡(jiǎn)單的模式, 就可以設(shè)計(jì)出高擴(kuò)展性, 低耦合的架構(gòu).
4.中間件等
更多信息請(qǐng)關(guān)注公眾號(hào):「軟件老王」,關(guān)注不迷路,軟件老王和他的IT朋友們,分享一些他們的技術(shù)見解和生活故事。
