Java動態代理的學習
阿新 • • 發佈:2018-11-19
說動態代理之前,先說一下spring對事物的管理。我們都知道Spring有兩大概念,即IOC(控制反轉)和AOP(面向切面程式設計),spring就是利用AOP的原理來實現對事物的管理,而AOP又是使用了動態代理,那具體是怎麼做的呢?簡單說明一下:
在未使用框架之前,比如使用JDBC階段,每次使物件入庫做save操作的時候,我們都需要手動的去開啟連線,提交事物,關閉連線,一萬次save操作,就要開啟一萬次連線,提交一萬次事物,關閉一萬次連線。我們就想著抽取一些共性來,將相同的操作提取出來做一些優化,相同的操作是什麼?開啟連線、關閉連線,這兩步是一樣的,對於執行儲存操作的方法肯定每次存取的值不同,不能夠抽取。那與動態代理有什麼關聯呢?動態代理一個作用就是實現對某個方法的增強,而這個方法就是save方法,我們只需要建立一個代理,讓代理每次遇到save方法的時候,就將抽取出來的開啟連線、關閉連線的操作應用到save方法上,就簡單很多,不用自己去手動控制了,”動態“,是指程式在執行時。
文章中用到的名詞解釋:被代理類和代理類的關係,類似於淘寶商家把貨物委託到淘寶平臺去銷售
被代理類:淘寶的商家
代理類:相當於“淘寶”的角色
處理程式:委託的整個流程
一、正文開始,首先我們需要建立一個統一的介面——人,正常人都需要工作,這是人的共性
package com.sinosoft.test;
public interface Person {
void work();
}
二、程式設計師也需要工作,工作內容就比如是將資料入庫,他實現了Person的介面
package com.sinosoft.test; /** * 被代理的類 */ public class ITMan implements Person { @Override public void work() { System.out.println("儲存資料入庫"); } }
三、處理程式Handler類,裡面有一個invoke方法,可以在執行儲存操作之前自動開啟資料庫連線,執行完儲存操作以後自動關閉資料庫連線
package com.sinosoft.test; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** *請求處理類,相當於代理類要執行“被代理類所實現介面中的方法” *就要先呼叫這個處理類中的處理程式 */ public class MyHandler implements InvocationHandler { public Object obj;//定義“被代理類”的引用 public MyHandler(Object obj){ this.obj=obj; } /** * 代理類呼叫了某個方法,就會來呼叫這個處理程式,就是下面的invoke方法, * 第一個引數基本不用,第二個引數是傳過來的方法,第三個引數是傳過來方法的引數陣列 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); //反射:相當於執行“被代理類”的method方法--即傳過來的work方法 method.invoke(obj, args); after(); return null; } public void before(){ System.out.println("開啟資料庫的連線"); } public void after(){ System.out.println("關閉資料庫的連線"); } /** *每個代理類都要有一個與之關聯的InvocationHandler,因為代理類本身並不處理方法, *而是交給它的handler去處理它的invoke方法 */ }
四、測試類, 目的是建立代理物件,讓代理物件去執行被代理物件的方法,實現每次入庫前自動開啟連線,入庫以後自動關閉連線。詳細解釋都在程式碼註釋裡面。
package com.sinosoft.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/***
* 動態代理:目的是實現方法的增強
* 建立代理類的步驟:
* 1、建立”被代理類“的物件
* 2、呼叫處理程式類即Handler類的構造,來建立InvocationHandler物件
* 3、使用java提供的proxy類的newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler handler)方法來建立代理類物件
*
*/
public class TestProxy {
public static void main(String[] args) {
//建立“被代理類”的物件,需要代理誰,就建立誰
ITMan man = new ITMan();
//InvocationHandler是代理物件的“呼叫處理程式”的入口
InvocationHandler handler = new MyHandler(man);
/**
* 生成一個代理物件,這個物件即不是ITMan的例項,也不是MyHandler的例項,它是執行期間動態生成的那個例項,這個例項
* 實現了被代理類實現的介面--即ITMan.class.getInterfaces(),也就是實現了person介面,所以根據多型轉換成了
* Person介面型別
*/
//引數說明:(定義代理類的類載入器,代理類要實現的介面列表,指派方法呼叫的呼叫處理程式)
Person proxy=(Person)Proxy.newProxyInstance(TestProxy.class.getClassLoader(), ITMan.class.getInterfaces(), handler);
//讓代理類去呼叫handler的處理程式,即invoke
proxy.work();
}
/**
* 當我們需要建立一個代理物件的時候,就使用它的newProxyInstance()方法,改方法主要是完成了兩件事情,首先是動態的建立了一個類,然後生成該類的例項
* 建立完這個類,首先首先得載入到記憶體裡面去,就是用這個類載入器完成的
*/
}