前三篇詳細總結了Mybatis的基本特性、經常使用配置、映射器,相對於Hibernate,映射器的配置相對複雜,但有很好的靈活性和擴展性,能夠應對各類業務場景。熟練掌握這些內容,能夠流暢的使用MyBatis進行開發了。java
後面準備介紹MyBatis的解析和運行原理以及自定義插件,今天看了書籍的這部分,都會涉及到反射和動態代理這些基礎,本篇文章總結下這些,便於理解原理。安全
文章索引:
微信
經過本篇的介紹,你會了解到:框架
首先看看官網對反射的定義:jvm
能夠經過java代碼,獲取當前加載類的字段、方法、構造函數等信息,並在安全限制內,使用反射字段、方法、構造函數進行操做。函數
簡單來講,能夠在運行時得到程序中每個類型的成員信息。程序中定義的對象,其類型都是在編譯期肯定的,而反射能夠動態地建立對象,並訪問或調用其成員。post
所謂代理,是一我的或組織代替另外一我的或組織作事,主要有3個角色:訪問者、代理人、被代理人,訪問者經由代理人,與被代理人交互,中間會加入一些本身的處理。測試
所謂的動態代理,是說在編譯時不須要定義代理類,而是在運行時建立,這個是關鍵:在運行時建立代理類。優化
Class類是一個實實在在的類,存在於java.lang包中,用來表示運行時類型信息。Class對象表示自定義類的類型信息,好比建立一個User類,JVM就會建立一個User對應的Class對象,保存User類相關的類型信息,該對象保存在jvm堆中,做爲訪問方法區中User類型信息的接口。this
在使用自定義類時,會首先檢查這個類的Class對象是否已經加載,若是沒有加載,默認的類加載器就會先根據類名查找.class文件,Class對象就會被加載到內存。
能夠經過下面3種方法獲取Class對象:
Class對象是反射的基礎,提供了獲取類信息的方法,後面會介紹。
java反射框架主要提供如下內容:
下面舉例說明相關功能
建立實例:
//獲取String所對應的Class對象
Class<?> c = User.class;
//獲取String類帶一個String參數的構造器
Constructor constructor = c.getConstructor(String.class);
//根據構造器建立實例
User user = (User)constructor.newInstance("calm");
複製代碼
獲取方法:
//返回類或接口聲明的全部方法,包括私有的,但不包括繼承的方法
public Method[] getDeclaredMethods() throws SecurityException
//全部public方法,包括繼承的方法
public Method[] getMethods() throws SecurityException
//返回一個特定的方法,第一個參數爲方法名稱,後面的參數爲方法參數對應Class的對象
public Method getMethod(String name, Class<?>... parameterTypes) 複製代碼
調用方法:
Class<?> userClass=User.class;
Object obj = userClass.newInstance();
Method method =klass.getMethod("addRole",String.class);
method.invoke(obj,"超級管理員");
複製代碼
JDK自己提供了動態代理的實現,要求被代理者必須實現接口。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) 複製代碼
第一個參數爲類加載器,第二個參數是被代理者實現的接口列表,第三個參數是實現了InvocationHandler接口的對象。
InvocationHandler是一個接口,用於規範執行被代理者的方法,可在執行方法先後,添加公共的處理代碼。生成的動態代理類包含一個InvocationHandler屬性,調用對應方法時,會觸發invoke方法的調用。
public class JDKProxy implements InvocationHandler {
private Object targetObject;//被代理對象
public Object newProxy(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)//invoke方法 throws Throwable {
Object ret = null;
ret = method.invoke(targetObject, args);
return ret;
}
}
複製代碼
測試代碼:
JDKProxy jdkProxy=new JDKProxy();
UserService userService = (UserService)
jdkProxy.newProxy(new UserServiceImp());
userService.addRole("超級管理員");
複製代碼
JDK動態代理的基本原理是根據定義好的規則,用傳入的接口建立一個新類。
JDK動態代理要求必須有接口,CGLIB(Code Generate Library)動態代理沒有這個要求,它是經過建立一個被代理類的子類,而後使用ASM字節碼庫修改代碼來實現的。
public class CGLibProxy implements MethodInterceptor {
private Object targetObject; //被代理對象
public Object createProxyObject(Object obj) {
this.targetObject = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
Object proxyObj = enhancer.create();
return proxyObj;
}
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object obj = null;
obj = method.invoke(targetObject, args);
return obj;
}
}
複製代碼
測試代碼:
CGLibProxy cgLibProxy=new CGLibProxy();
UserService userService = (UserService)
cgLibProxy.newProxy(new UserServiceImp());
userService.addRole("超級管理員");
複製代碼
ASM 是一個 Java 字節碼操控框架。它可以以二進制形式修改已有類或者動態生成類。不過ASM在建立class字節碼的過程當中,操縱的級別是底層JVM的彙編指令級別,這要求ASM使用者要對class組織結構和JVM彙編指令有必定的瞭解。另外可使用javassist框架操做字節碼,它對開發者提供的接口比較優化。
瞭解了反射和動態代理,對後面介紹MyBatis的解析和運行原理有很大幫助,下一篇會重點介紹。
歡迎掃描下方二維碼,關注個人我的微信公衆號 ~