Java動態代理的總結
來自: http://www.cnblogs.com/maybo/p/5193843.html
最近和一個好友在聊起Mybatis時,他問用Mybatis我們只是配置好mapper,然后寫dao層接口就實現了dao層方法。然后我說我覺得用動態代理可以實現。然后他又說感覺動態代理和外觀模式沒什么區別,我說:用動態代理模式時你想在一些代理服務器如Magent(給memcached)提供代理服務時,你調用memcached的接口和Magent,在如你用Nginx做代理服務器時,訪問Ngix的http的url并沒有因為用了代理服務器就發生變化,所以我說代理模式和外觀有一個很明顯區別是代理模式接口和需要代理的服務接口一樣而且代理模式并不做處理,處理還是需要代理的服務,例如在用Magent他只是做了一些服務器備份,以及路由,負載均衡的處理,而實際的命令還是交給memcached來執行。進天閑暇時間就來總結一下代理模式,以及jdk,cglib代理模式用法,來理解代理模式。
一. JAVA的動態代理(比較官方說法)
代理模式
代理模式是常用的java設計模式,他的特征是代理類與委托類有同樣的接口,代理類主要負責為委托類預處 理消息、過濾消息、把消息轉發給委托類,以及事后處理消息等。 代理類與委托類之間通常會存在關聯關系,一個代理類的對象與一個委托類的對象關聯,代理類的 對象本身并不真正實現服務,而是通過調用委托類的對象的相關方法,來提 供特定的服務。
按照代理的創建時期,代理類可以分為兩種。
靜態代理:由程序員創建或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。
動態代理:在程序運行時,運用反射機制動態創建而成。
二. 動態代理實現
java.lang.reflect.Proxy,
Proxy 提供用于創建動態代理類和實例的靜態方法.
newProxyInstance()
返回一個指定接口的代理類實例,該接口可以將方法調用指派到指定的調用處理程序。
2.1. Dao接口(提供模擬數據訪問層接口)
package javaproxy; /*
- @author:maybo
- @time:2016/2/16
定義一個數據訪問層接口 */ public interface Dao { //模擬數據保存 public void save(); }</pre>
2.2. DaoImpl類實現類
package javaproxy;
public class DaoImpl implements Dao{
@Override
public void save() {
System.out.println("執行一個保存方法。。。。。。。。。。。。");
}
}</pre>
2.3. 代理處理類
package javaproxy;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method;
public class DaoHandler implements InvocationHandler{ private Object obj; public DaoHandler(Object obj) { this.obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("do something before method");//這里模擬AOP的前置方法 Object ret = method.invoke(this.obj, args); System.out.println("do something after method");//這里模擬AOP的后置方法 return ret; }
}</pre>
2.4. client調用
package javaproxy;import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) { // 元對象(被代理對象) DaoImpl daoImpl = new DaoImpl(); // 業務代理類 DaoHandler daoHandler=new DaoHandler(daoImpl); Dao dao=(Dao) Proxy.newProxyInstance(daoImpl .getClass().getClassLoader(), daoImpl.getClass() .getInterfaces(), daoHandler); dao.save(); }
}</pre>
2. 5. 結果
3. 模擬Mybatis中的代理實現
3.1. MapperProxy類
package javaproxy;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
public class MapperProxy implements InvocationHandler { @SuppressWarnings("unchecked") /*
* 這里通過靜態方法得到實現類的對象 * * @param:接口 * * @param:用sqlsession執行方法 * * @return: 返回代理對像 */ public static <T> T newMapperProxy(Class<T> mapperInterface, Object sqlSession) { ClassLoader classLoader = mapperInterface.getClassLoader(); Class<?>[] interfaces = new Class[] { mapperInterface }; MapperProxy proxy = new MapperProxy(); return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy); } /* * (non-Javadoc) * * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, * java.lang.reflect.Method, java.lang.Object[]) * * @param:代理對象 * * @param:方法通過方法名字找到對應的方法 * * @param:通過方法傳入對象找到對應的傳遞參數映射 * * @return:返回執行后的參數對象 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 這里通過方法名字以及參數通過解析對應的mapper來執行對應的操作 System.out.println("在這里執行實際方法"); return null; }
}</pre>
3.2. Client
package javaproxy;import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) { Dao dao=MapperProxy.newMapperProxy(Dao.class, null); dao.save(); }
}</pre>
3.3. 結果
以上是使用JDK動態代理的例子。至于使用cglib的例子在spring基礎說明中有介紹。
</div>