前言:spring中AOP的原理就是java的動態代理機制,動態代理又與反射相關,所以回顧一下反射與動態代理的知識。 反射
Jvm利用類載入器將.class檔案載入到jvm記憶體中,.class檔案的二進位位元組流轉換為方法區的運行時資料結構,儲存著類object的版本,欄位,方法,介面等資訊,同時在堆中產生每個類唯一的類型對象class對象,作為方法區類資訊的訪問入口。
Java反射機制讓我們在編譯期之外的運行期獲得任何一個類的class對象,得到方法區中的類的介面,方法,欄位等資訊,也可以在運行期執行個體化對象。 執行個體化Class對象:
Class<?> demo1 = Class.forname(“Reflect.name”);//通過全限定名執行個體化Class對象Class<?> demo2 = new Demo().getInstance();Class<?> demo3 = Demo.class;
通過一個執行個體對象擷取完整包名和類名:
demo1.getClass().getName(); 通過Class對象執行個體化類的執行個體
a)無參構造器執行個體化: Person p = (Person) demo1.newInstance();
b)有參構造器執行個體化,先擷取構造器:Constructor<?> cons[] = demo.getConstructors();Person p1 = (Person)cons[1].newInstance(“Rollen”);返回一個類的介面:Class<?> demo = Class.forname(“Reflect.person”);//儲存所有的介面Class<?> intes[] = demo.getInterfaces();intes[i].getName();
取得其他類的父類:
Class<?> temp = demo.getSuperclass();temp.getName();
擷取其他類的建構函式:
Constructor<?> cons[] = demo.getConstructors();
擷取其他類的屬性(欄位):
//本類屬性 (比如: public string name)
Field[] field = demo.getDeclaredFields();
//許可權修飾符
int mo = field[i].getModifiers();
String priv = Modifier.toString(mo);
//屬性類型
Class
//調用Person類中的sayChina方法Method method = demo.getMethod(“sayChina”);method.invoke(demo.newInstance());//調用Person類中的sayHello方法Method method = demo.getMethod(“sayHello”,String.class,int.class);method.invoke(demo.newInstance(),”Rollen”,20);
通過反射操作屬性:
Class<?> demo = Class.forname(“Reflect.Person”);Object obj = demo.newInstance();Field field = demo.getDeclaredField(“sex”);field.setAccessible(true);field.set(obj,”男”);//設定sex屬性為“男”
動態代理機制
動態代理機制中有一個重要的類Proxy和一個重要介面InvocationHandler。先牢記三個概念:1.動態代理類,每一個動態代理類都是InvocationHandler的子類。2.代理對象,由Proxy.newProxyInstance(…)建立的代理對象,每一個代理對象都會關聯一個動態代理類執行個體,當代理對象調用真實對象方法時會轉換為對handler動態代理類的invoke方法的調用。 3.真實對象,我們想要代理的對象。
介紹完動態代理類,代理對象和真實對象的概念,我們通過一個執行個體來真正地瞭解動態代理模式是如何?的:
首先定義一個Subject介面,定義rent()方法和hello()方法:
package Invocation;/** * Created by kang on 17/9/28. */public interface Subject { public void rent(); public void hello(String hello);}
定義一個realSubject介面,這個類是真實對象,也就是被代理對象:
package Invocation;/** * Created by kang on 17/9/28. *///真實對象public class realSubject implements Subject { @Override public void rent() { System.out.println("I want to rent my house!"); } @Override public void hello(String hello) { System.out.println("hello " +hello); }}
定義一個動態代理類,每一個動態代理類都需要實現InvocationHandler介面,在動態代理類中傳入真實對象,然後每個代理對象綁定一個動態代理類執行個體,且每個動態代理類均有一個invoke方法。
package Invocation;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;/** * Created by kang on 17/9/28. *///動態代理類MyInvocationHandler是InvocationHandler的子類,必須實現invoke方法public class DynamicProxy implements InvocationHandler { //要代理的真實對象 private Object object; //給要代理的真實對象賦值 public DynamicProxy(Object object){ this.object = object; } /** * * @param proxy 指創造的代理對象 * @param method 指我們要代理的真實對象的某個方法的Method對象 * @param args 指真實對象的某個方法的參數 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在代理真實對象前添加我們添加一些自己的操作 System.out.println("before rent house"); System.out.println("Method:" + method); //當代理對象調用真實對象的方法時,會自動跳轉到動態代理類即InvocationHandler的子類的invoke方法來調用 method.invoke(object,args); //代理真實對象後添加一些操作 System.out.println("after rent house"); return null; }}
查看Client類:
package Invocation;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;/** * Created by kang on 17/9/28. */public class Client { public static void main(String[] args) { //subject是真實對象,handler是動態代理類,往動態代理類傳入真實對象 Subject realsubject = new realSubject(); InvocationHandler handler = new DynamicProxy(realsubject); /** * 通過Proxy的newProxyInstance方法建立代理對象 * 1.第一個參數handler.getClass().getClassLoader()表示用動態代理類的類載入器載入代理對象 * 2.第二個參數realSubject.getClass().getInterfaces()傳入真實對象的介面,所以代理對象也可以調用介面,使用真實對象的方法。 * * 3.第三個對對象handler讓代理對象與動態代理類聯絡起來,當代理對象調用真實對象的方法時可以自動跳轉到執行handler的invoke方法。 * */ Subject subject = (Subject) Proxy.newProxyInstance( handler.getClass().getClassLoader(),realsubject.getClass().getInterfaces(),handler); System.out.println(subject.getClass().getName()); subject.rent(); subject.hello("nihao"); }}
我們先來看看控制台的輸出:
com.sun.proxy.$Proxy0before rent houseMethod:public abstract void Invocation.Subject.rent()I want to rent my house!after rent housebefore rent houseMethod:public abstract void Invocation.Subject.hello(java.lang.String)hello nihaoafter rent house