代理模式使用代理對象完成用戶的請求,屏蔽用戶對真實對象的訪問。
代理模式的用途很多,比如因為安全原因,需要屏蔽客戶端直接訪問真實對象;或者在遠程調用中,需要使用代理對象處理遠程方法中的技術細節;或者為了提升系統,對真是對象進行封裝,從而達到延遲加載的目的。
在系統啟動時,將消耗資源最多的方法使用代理模式分離,就可以加快系統的啟動速度,減少用戶的等待時間。在用戶真正在做查詢是,再由代理類加載真實的類,完成用戶請求。這就是使用代理模式達到延遲加載的目的。
1.靜態代理實現:
主題接口:
1
2
3
|
public interface IDBQuery { String request(); } |
真實主題:
1
2
3
4
5
6
7
8
9
10
11
12
|
public class DBQuery implements IDBQuery { public DBQuery(){ try { Thread.sleep( 10000 ); } catch (Exception e) { e.printStackTrace(); } } public String request() { return "string request" ; } } |
代理類:
1
2
3
4
5
6
7
8
|
public class IDBQueryProxy implements IDBQuery { private DBQuery dbquery; public String request() { if (dbquery== null ) dbquery = new DBQuery(); return dbquery.request(); } } |
最后,主函數:
1
2
3
4
5
6
|
public class ProxyText { public static void main(String[] args) { IDBQuery dbquery = new IDBQueryProxy(); System.out.println(dbquery.request()); } } |
靜態代理注意,代理類是真實類實現共同的接口,并且代理類引用真實類對象,將耗時操作放在代理類方法中實現。
動態代理:
動態代理即運行時,動態生成代理類。即:代理類的字節碼在運行時生成并載入當前的classloader。與靜態代理相比,動態代理不需要為真實注意封裝一個形式上完全一樣的封裝類,假如主題接口很多,就要為每一個接口寫一個代理方法是很煩人的,如果接口有變動,真實類和代理類都需要變化,這樣不利于系統維護;其次,使用一些動態代理的生成方法甚至可以在運行是指定代理類的執行邏輯,從而大大提高的系統的靈活性。
主題接口:
1
2
3
|
public interface IDBQuery { String request(); } |
jdk代理類:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class JdbDbqueryHandler implements InvocationHandler{ IDBQuery idbquery = null ; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (idbquery== null ){ idbquery = new DBQuery(); } return idbquery.request(); } public static IDBQuery createJdbProxy(){ IDBQuery jdkProxy = (IDBQuery) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{IDBQuery. class }, new JdbDbqueryHandler()); System.out.println( "JdbDbqueryHandler.createJdbProxy()" ); return jdkProxy; } } |
主函數:
1
2
3
4
5
6
|
public class ProxyText { public static void main(String[] args) { IDBQuery idbQuery = JdbDbqueryHandler.createJdbProxy(); System.out.println(idbQuery.request()); } } |
另外,也可以使用CGLIB和javassist動態代理與jdk動態代理類似,但是jdk動態類的創建過程最快,因為這個內置實現的difineclass()方法被定義為native實現,故性能優于其他。在代理類的函數調用上,JDK的動態代理不如CGLIB和javassist動態代理,而javassist動態代理性能質量最差,甚至不如JDK的實現。在實際開發應用中,代理類的方法調用頻率要遠遠高于代理類的實際生成頻率,故動態代理的方法調用性能應該成為性能的關注點。JDK動態代理強制要求代理類和真是主題實現統一接口,CGLIB和javassist動態代理沒有這樣的要求。
在java中,動態代理的實現涉及到classloader的使用,以CGLIB為例,簡要描述下動態類的加載過程。使用CGLIB生成動態代理,首先需要生成Enhancer類的實例,并制定用于處理代理業務的回調類。在enhancer.create()方法中,會使用DefaultGeneratorStrategy.Generate()方法生成代理類的字節碼,并保存在byte數組中。接著調用reflectUtils.defineClass()方法,通過反射,調用ClassLoader.defineClass()方法,將字節碼裝載到classloader中,完成類的加載。最后,通過reflectUtils.newInstance()方法,通過反射生成動態類實例,并返回該實例。其他與該過程細節不同,但是生成邏輯相同。
以上就是本文的全部內容,希望對大家的學習有所幫助。