什麼事代理?
就是對一個對象功能的增強,例如網上售票,代理的就是各個售票點的代理
java實現的代理兩種辦法
名詞:代理對象、 目標對象 。代理和目標不是絕對的,例如:故宮售票、網上售票、黃牛售票。故宮售票對於網上售票來說,前者屬於目標對象,後者屬於代理對象,網上售票和黃牛售票也是同理,所以代理對象與目標對象不是絕對的,會隨着代碼的改變而改變。
靜態代理:
繼承:代理對象繼承目標對象,重寫需要增強的方法
缺點:對象太多,複雜。
下面代碼模擬靜態繼承代理
1、父類dao
package dao; public class IndexDao implements Dao { public void query() { System.out.println("IndexDao_Query"); } }
2、子類(繼承靜態代理)
package dao; public class LogDao extends IndexDao { @Override public void query() { System.out.println("插入日誌_LogDao"); super.query(); } }
3、測試
package test; import dao.Dao; import dao.LogDao; import dao.TimeDao; public class ProxyStaticTest { public static void main(String args[]){ Dao dao = new LogDao(); dao.query(); Dao dao1 = new TimeDao(); dao1.query(); } }
4、截圖
聚合:目標對象和代理對象實現同一接口,代理對象當中要包含目標對象(通過構造或者set),再次重新調用目標對象的方法並增強此方法
缺點:也會產生過多的類(內存溢出)
下面代碼模擬靜態聚合代理
1、日誌dao
package dao;
public class LogDao {
Dao dao;
public LogDao(Dao dao) {
this.dao = dao;
}
public void query() {
System.out.println("日誌管理——LogDao");
dao.query();
}
}
2、測試
package test; import dao.Dao; import dao.LogDao; import dao.TimeDao; public class ProxyStaticTest { public static void main(String args[]){ Dao dao1 = new TimeDao(); LogDao LogDao = new LogDao(dao1); LogDao.query(); } }
3、截圖
總結:靜態代理只適合確定類的數量的情況下才能使用,否則就會出現類爆炸(類過多的問題)
擴展:聚合靜態代理很類似裝飾者設計模式,只不過裝飾者設計模式是用set方法將對象賦值。而聚合代理是用構造方法將對象賦值(IO中的類是用的就是裝飾者設計模式)
相關博客:https://www.cnblogs.com/ChrisRIM/archive/2012/08/21/2648372.html
動態代理
1、接口
package com.dao; public interface ObjectDao { public void query(); }
2、實現類
package com.dao; public class User_Defined_Dao implements ObjectDao { public User_Defined_Dao() { } public void query() { System.out.println("自定義Dao中的query方法"); } }
3、代理類
package com.proxy; /* * 對象是如何生成的? * java * class * new * **/ import javax.tools.JavaCompiler; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import java.io.File; import java.io.FileWriter; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; public class ProxyUtil { public static Object getInstance(Object target) { Object proxy = null; Class targetInfo = target.getClass().getInterfaces()[0]; String tab = "\t"; String line = "\n"; String implName = targetInfo.getSimpleName(); //創建java內容 String javaContent = ""; //package String packageContent = "package com.proxy;" + line; //importClass String impPackageContent = "import " + targetInfo.getName() + ";" + line; //創建類體 String classContent = "public class $Proxy implements " + implName + " {" + line; //創建私有變量 String privateObject = tab + "private " + implName + " target;" + line; //創建構造 String constructorContent = tab + "public $Proxy (" + implName + " target ){" + line; constructorContent = constructorContent + tab + tab + "this.target = target;" + line; constructorContent = constructorContent + tab + "}" + line; //創建方法 String methedContent = ""; Method[] methods = targetInfo.getDeclaredMethods(); for (Method method : methods) { //獲取方法的返回類型 String methodTypeName = method.getReturnType().getSimpleName(); //獲取方法的名字 String methodName = method.getName(); methedContent = tab + "public " + methodTypeName + " " + methodName + " ("; //創建參數 Object[] args = method.getParameterTypes(); String argContent = ""; for (int i = 0; i < args.length - 1; i++) { //獲取參數的類型 String argsTypeName = args[i].getClass().getSimpleName(); //獲取參數名稱 i1 i2 argContent = argsTypeName + " i" + i; if (i != args.length - 1) { //多個參數的情況下需要使用','但是最後一個不需要 argContent += ","; } } //組裝方法內容,方法體中的邏輯先寫死 methedContent += argContent + "){" + line + tab + tab + "System.out.println(\"自定義Dao方法\");" + line + tab; methedContent += tab + tab + "target." + methodName + "(" + argContent + ");"; methedContent += line + tab + "}"; } javaContent = packageContent + impPackageContent + classContent + privateObject + constructorContent + methedContent + line + "}"; //1、使用IO字符流將創建好String 放到D盤中,用於查看是否存在問題。 String filePath = "D:\\com\\proxy\\"; String classFileName = "com.proxy.$Proxy"; File fileDir = new File("D:\\com\\proxy\\"); try { if (!fileDir.isDirectory()) { fileDir.mkdirs(); } File file = new File("D:\\com\\proxy\\$Proxy.java"); if (!file.exists()) { file.createNewFile(); } FileWriter fileWriter = new FileWriter(file); fileWriter.write(javaContent); fileWriter.flush(); fileWriter.close(); //創建java編譯器 JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); //第三方管理器 StandardJavaFileManager fileMgr = javaCompiler.getStandardFileManager(null, null, null); //將java文件放到管理器中 Iterable units = fileMgr.getJavaFileObjects(file); //創建編譯任務 JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileMgr, null, null, null, units); //開始啓動任務 task.call(); fileMgr.close(); //使用反射獲取編譯後的$Proxy對象 URL [] urls = new URL[]{new URL("file:D:\\\\")}; URLClassLoader ucl = new URLClassLoader(urls); Class clazz = ucl.loadClass(classFileName); Constructor constructor = clazz.getConstructor(targetInfo); proxy = constructor.newInstance(target); System.out.println("成功!"); } catch (Exception e) { System.out.println("失敗!"); e.printStackTrace(); } return proxy; } }
4、測試
public static void main(String args[]){ ObjectDao objectDao = (ObjectDao) ProxyUtil.getInstance(new User_Defined_Dao()); objectDao.query(); }
5測試結果