Java反射與代理,Java反射代理
Java反射機制與動態代理,使得Java更加強大,Spring核心概念IoC、AOP就是通過反射機制與動態代理實現的。
1 Java反射
樣本:
User user = new User();user.setTime5Flag("test"); Class<?> cls = Class.forName("com.test.User");//介面必須public,無論是否在本類內部使用!或者使用cls.getDeclaredMethod(),或者遍曆修改可訪問性Method method = cls.getMethod("getTime5Flag");String res1 = (String) method.invoke(user);System.out.println(res1);//涉及到基本類型如int,則使用int.class!Integer.class!=int.class!method = cls.getMethod("setTime5Flag", String.class); method.invoke(user, "Rollen");method = cls.getMethod("getTime5Flag");String res2 = (String) method.invoke(user);System.out.println(res2);
通過一個對象獲得完整的包名和類名:
user.getClass().getName();//全路徑類名user.getClass().getSimpleName();//無包名的類名
擷取class:
Class.forName("com.test.User");com.test.User.class;user.getClass();
通過class執行個體化一個對象
User user = (User) cls.newInstance();//必須有無參建構函式
取得全部建構函式
Constructor<?> cons[]=cls.getConstructors(); //按聲明順序返回cons[0].newInstance();//無顯示聲明,則有預設建構函式
取得一個類所實現的所有interface
Class<?> intes[] = cls.getInterfaces();
取得父類
cls.getSuperClass();
取得修飾符
int mo = cls.getModifiers();int mo = cons[0].getModifiers();int mo = method.getModifiers();Modifier.toString(mo);
擷取方法參數
method.getParametors();cons[0].getParametors();
擷取方法參數類型
method.getParametorTypes();cons[0].getParametorTypes();
擷取方法聲明拋出的所有異常類型
method.getExceptionTypes();
擷取本類聲明的全部屬性
Field[] field = cls.getDeclaredFields(); //包括privatefield[0].getModifiers();field[0].getType();
擷取本類的全部公開屬性,包括父類聲明、介面聲明、本類聲明的所有public屬性
cls.getFields();
設定指定屬性可訪問
field.setAccessible(true);field.set(obj,’ces’);field.get(obj);
* getFields()與getDeclaredFields()區別:getFields()只能訪問類中聲明為公有的欄位,私人的欄位它無法訪問,能訪問從其它類繼承來的公有欄位;getDeclaredFields()能訪問類中所有的欄位,與public,private,protect無關,但不能訪問從其它類繼承來的欄位
* getMethods()與getDeclaredMethods()區別:getMethods()只能訪問類中聲明為公有的方法,私人的方法它無法訪問,能訪問從其它類繼承來的公有方法;getDeclaredMethods()能訪問類中所有的欄位,與public,private,protect無關,不能訪問從其它類繼承來的方法
* getConstructors()與getDeclaredConstructors()區別:getConstructors()只能訪問類中聲明為public的建構函式;getDeclaredConstructors()能訪問類中所有的建構函式,與public,private,protect無關
通過反射擷取並修改數組的資訊
int[] temp={1,2,3,4,5};Class<?> demo = temp.getClass().getComponentType();System.out.println("數群組類型: "+demo.getName());//intSystem.out.println("數組長度: "+Array.getLength(temp));//5System.out.println("數組的第一個元素: "+Array.get(temp, 0));//1Array.set(temp, 0, 100);System.out.println("修改之後數組第一個元素為: "+Array.get(temp, 0));//100
擷取數群組類型
cls.getComponentType();
判斷是否是數群組類型
cls.isArray();
2 Java代理
代理模式是常用的Java設計模式,它的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預先處理訊息、過濾訊息、把訊息轉寄給委託類,以及事後處理訊息等。代理類與委託類之間通常會存在關聯關係,一個代理類的對象與一個委託類的對象關聯,代理類的對象本身並不真正實現服務,而是通過調用委託類的對象的相關方法,來提供特定的服務。
按照代理的建立時期,代理類可以分為2種。
- 靜態代理:由程式員建立或特定工具自動產生原始碼,再對其編譯。在程式運行前,代理類的.class檔案就已經存在了。
- 動態代理:在程式運行時,由Java反射機制動態產生位元組碼。
2.1 靜態代理
public interface Count { public void queryCount();}public class CountImpl implements Count { public void queryCount() { System.out.println("查看賬戶方法..."); }}//代理類public class CountProxy implements Count { private CountImpl countImpl; public CountProxy(CountImpl countImpl) { this.countImpl = countImpl; } @Override public void queryCount() { System.out.println("交易處理之前"); countImpl.queryCount(); // 調用委託類的方法; System.out.println("交易處理之後"); }} //測試類別public class TestCount { public static void main(String[] args) { CountImpl countImpl = new CountImpl(); CountProxy countProxy = new CountProxy(countImpl); countProxy.queryCount(); } }
觀察代碼可以發現每一個代理類只能為一個介面服務,這樣一來程式開發中必然會產生過多的代理,而且,所有的代理操作除了調用的方法不一樣之外,其他的操作都一樣,則此時肯定是重複代碼。解決這一問題最好的做法是可以通過一個代理類完成全部的代理功能,那麼此時就必須使用動態代理完成。
2.2 動態代理
動態代理類的位元組碼在程式運行時由Java反射機制動態產生,無需程式員手工編寫它的原始碼。動態代理類不僅簡化了編程工作,而且提高了軟體系統的可擴充性,因為Java 反射機制可以產生任意類型的動態代理類。
2.2.1 JDK動態代理
java.lang.reflect 包中的Proxy類和InvocationHandler 介面提供了產生動態代理類的能力。
InvocationHandler介面:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
參數說明:
Object proxy:指被代理的對象。
Method method:要調用的方法
Object[] args:方法調用時所需要的參數
可以將InvocationHandler介面的子類想象成一個代理的最終操作類,替換掉ProxySubject。
Proxy類:
Proxy類是專門完成代理的操作類,可以通過此類為一個或多個介面動態地產生實作類別,此類提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
參數說明:
ClassLoader loader:類載入器
Class<?>[] interfaces:得到全部的介面
InvocationHandler h:得到InvocationHandler介面的子類執行個體
如果想要完成動態代理,首先需要定義一個InvocationHandler介面的子類,以完成代理的具體操作。
interface Subject { public String say(String name, int age);}class RealSubject implements Subject { @Override public String say(String name, int age) { return name + " " + age; }}//JDK動態代理類class MyInvocationHandler implements InvocationHandler { private Object target = null; //綁定委派物件並返回一個代理類 public Object bind(Object target) { this. target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this); //要綁定介面(cglib彌補了這一點) } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(“before method!”); Object temp = method.invoke(target, args); System.out.println(“after method!”); return temp; }}class hello { public static void main(String[] args) { MyInvocationHandler demo = new MyInvocationHandler(); Subject sub = (Subject) demo.bind(new RealSubject()); String info = sub.say("Rollen", 20); System.out.println(info); }}
但是,JDK的動態代理依靠介面實現,如果有些類並沒有實現介面,則不能使用JDK代理,這就要使用cglib動態代理了。 2.2.2 CGLIB動態代理
JDK的動態代理機制只能代理實現了介面的類,而未實現介面的類就不能實現JDK的動態代理。
cglib是針對類來實現代理的,它的原理是對指定的目標類產生一個子類,並覆蓋其中方法實現增強,但因為採用的是繼承,所以不能對final修飾的類進行代理。
public interface BookFacade { public void addBook(); } public class BookFacadeImpl1 { public void addBook() { System.out.println("增加圖書的普通方法..."); } } import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; //cglib動態代理類public class BookFacadeCglib implements MethodInterceptor { private Object target; //綁定委派物件並返回一個代理類 public Object getInstance(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); // 回調方法 enhancer.setCallback(this); // 建立代理對象 return enhancer.create(); } @Override // 回調方法 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("事物開始"); Object temp = proxy.invokeSuper(obj, args); System.out.println("事物結束"); return temp; } } public class TestCglib { public static void main(String[] args) { BookFacadeCglib cglib = new BookFacadeCglib(); BookFacadeImpl1 bookCglib = (BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1()); bookCglib.addBook(); } }
參考:1.https://segmentfault.com/a/11900000043260402.http://blog.csdn.net/hintcnuie/article/details/10954631