Mybaties 中有個分頁插件,以前有特地的去了解了一下原理 :https://www.cnblogs.com/jonrain0625/p/11168247.html,從瞭解中得知分頁插件是基於Mybaties的攔截器去實現的,這個插件就是一個攔截器,和別的攔截器組成了Mybaties的攔截器鏈,而後全部的攔截器都對Executor 這個類 作了動態代理。本次主要的再次去學習下這個動態代理,去實現一個最基本的攔截器鏈的效果。固然還有spring aop 等不少地方都是基於動態代理去實現的,關於Aop能夠在 :http://www.javashuo.com/article/p-morvsgps-co.html 去了解。本次也是基於這篇文章,及代碼去學習和實現 攔截器鏈。html
java中代理模式分靜態代理和動態代理,而動態代理的實現有兩種實現方法,一種是基於JDK 用 接口方法去實現 ,一種是基於CGLIB 基於類去實現 ,瞭解能夠看:https://www.cnblogs.com/rinack/p/7742682.html 。java
1.建立代理類的接口spring
2.實現代理類執行的接口 InvocationHandler設計模式
3.生成代理對象:Proxy.newProxyInstance(loader, interfaces, h);ide
4.使用代理對象學習
示列實現對user類的log方法攔截 ,在執行log方法以前,攔截器鏈中 LogIntercept1 和LogIntercept2 對log 方法攔截 ,作業務邏輯,攔截器鏈優勢的很好體現是,實現耦合,能夠高度的作到對內修改 。測試
public interface Log { public void log(); }
public class User implements Log{ String name = "user1"; public void log() { System.out.println("user1 ----- 登錄"); } }
爲了封裝 , 在bin方法中調用 Proxy.newProxyInstance 建立代理對象 ,把代理對象 和攔截器注入到代理對象,在 invoke方法中用攔截器代理執行。this
public class Handler implements InvocationHandler{ //調用對象 private Object proxy; //目標對象 private Intercept intercept; private Handler(Intercept target,Object proxy) { this.intercept=target; this.proxy=proxy; } public static Object bind(Intercept target,Object proxy){ return Proxy.newProxyInstance( proxy.getClass().getClassLoader() , proxy.getClass().getInterfaces(), new Handler(target,proxy)); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return intercept.intercept(this.proxy,method,args); } }
攔截器和攔截器的實現,偷懶寫在一個文件中spa
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public interface Intercept { Object intercept(Object o, Method m, Object[] os ); } class LogIntercept1 implements Intercept { @Override public Object intercept(Object o, Method m, Object[] os) { try { System.out.println("LogIntercept1 攔截登錄操做 作相關業務邏輯"); return m.invoke(o,os); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); return null; } } } class LogIntercept2 implements Intercept { @Override public Object intercept(Object o, Method m, Object[] os) { try { System.out.println("LogIntercept2 攔截登錄操做,作相關業務邏輯"); return m.invoke(o,os); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); return null; } } }
在類中根據攔截器的數量,對代理類作循環。每次代理都把攔截器傳入代理對象中 。插件
package 設計模式.com.pox.logPoxy; import java.util.ArrayList; import java.util.List; public class ProxyFactory { List<Intercept> InterceptChain = new ArrayList<Intercept>() { private static final long serialVersionUID = 1L; { add(new LogIntercept1()); add(new LogIntercept2()); } }; public Object proxy(Class<?> classz) throws Exception { try { Object obj = classz.newInstance(); return InterceptAll(obj); } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException("代理異常");//拋出個異常,不另外設計異常類了,用RuntimeException 代替 } } /** 攔截器代理 * @param obj * @return */ private Object InterceptAll(Object obj) { if(InterceptChain.isEmpty()) { return obj; } for (Intercept intercept : InterceptChain) { obj = Handler.bind(intercept,obj); } return obj; } // 一下是單列的建立模式 public ProxyFactory(){ if(inner.proxyFactory != null) { throw new RuntimeException("不容許建立多個實例"); } } public static ProxyFactory getProxyFactory() { return inner.proxyFactory; } private static class inner{ static ProxyFactory proxyFactory = new ProxyFactory(); } }
public class Test { public static void main(String[] args) throws Exception { ProxyFactory proxyFactory = ProxyFactory.getProxyFactory(); Log user = (Log) proxyFactory.proxy(User.class); user.log(); } } /** ouput : LogIntercept2 攔截登錄操做 LogIntercept1 攔截登錄操做 user1 ----- 登錄 */
以上就是一個簡單的攔截器鏈實現,能夠去查閱Mybaties的攔截器鏈,其原理是同樣的,若是業務須要增長個攔截器鏈,實現接口 Intercept ,添加到代理工廠 ProxyFactory 攔截器鏈 InterceptChain中便可,實現高度的解耦功能。