轉載:http://blog.csdn.net/luanlouis/article/details/24589193class文件簡介及加載
b. 自定義一個類加載器:
c. 然后編譯成Programmer.class文件,在程序中讀取字節碼,然后轉換成相應的class對象,再實例化:
以上代碼演示了,通過字節碼加載成class 對象的能力,下面看一下在代碼中如何生成class文件的字節碼。
在運行期的代碼中生成二進制字節碼
Java字節碼生成開源框架介紹--ASM:
下面通過ASM 生成下面類Programmer的class字節碼:
使用ASM框架提供了ClassWriter 接口,通過訪問者模式進行動態創建class字節碼,看下面的例子:
上述的代碼執行過后,用Java反編譯工具(如JD_GUI)打開D盤下生成的Programmer.class,可以看到以下信息:
Java字節碼生成開源框架介紹--Javassist:
代理的基本構成:
InvocationHandler角色的由來
|
static Object |
newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 返回一個指定接口的代理類實例,該接口可以將方法調用指派到指定的調用處理程序。 |
在調用代理對象中的每一個方法時,在代碼內部,都是直接調用了InvocationHandler 的invoke方法,而invoke方法根據代理類傳遞給自己的method參數來區分是什么方法。
Object |
invoke(Object proxy,Method method,Object[] args) 在代理實例上處理方法調用并返回結果。 |
講的有點抽象,下面通過一個實例來演示一下吧:
JDK動態代理示例
現在定義兩個接口Vehicle和Rechargable,Vehicle表示交通工具類,有drive()方法;Rechargable接口表示可充電的(工具),有recharge() 方法;
定義一個實現兩個接口的類ElectricCar,類圖如下:
通過下面的代碼片段,來為ElectricCar創建動態代理類:
- package com.foo.proxy;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Proxy;
- public class Test {
- public static void main(String[] args) {
- ElectricCar car = new ElectricCar();
- // 1.獲取對應的ClassLoader
- ClassLoader classLoader = car.getClass().getClassLoader();
- // 2.獲取ElectricCar 所實現的所有接口
- Class[] interfaces = car.getClass().getInterfaces();
- // 3.設置一個來自代理傳過來的方法調用請求處理器,處理所有的代理對象上的方法調用
- InvocationHandler handler = new InvocationHandlerImpl(car);
- /*
- 4.根據上面提供的信息,創建代理對象 在這個過程中,
- a.JDK會通過根據傳入的參數信息動態地在內存中創建和.class 文件等同的字節碼
- b.然后根據相應的字節碼轉換成對應的class,
- c.然后調用newInstance()創建實例
- */
- Object o = Proxy.newProxyInstance(classLoader, interfaces, handler);
- Vehicle vehicle = (Vehicle) o;
- vehicle.drive();
- Rechargable rechargeable = (Rechargable) o;
- rechargeable.recharge();
- }
- }
- package com.foo.proxy;
- /**
- * 交通工具接口
- * @author louluan
- */
- public interface Vehicle {
- public void drive();
- }
- package com.foo.proxy;
- /**
- * 可充電設備接口
- * @author louluan
- */
- public interface Rechargable {
- public void recharge();
- }
- package com.foo.proxy;
- /**
- * 電能車類,實現Rechargable,Vehicle接口
- * @author louluan
- */
- public class ElectricCar implements Rechargable, Vehicle {
- @Override
- public void drive() {
- System.out.println("Electric Car is Moving silently...");
- }
- @Override
- public void recharge() {
- System.out.println("Electric Car is Recharging...");
- }
- }
來看一下代碼執行后的結果:
- package com.foo.proxy;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- public class InvocationHandlerImpl implements InvocationHandler {
- private ElectricCar car;
- public InvocationHandlerImpl(ElectricCar car)
- {
- this.car=car;
- }
- @Override
- public Object invoke(Object paramObject, Method paramMethod,
- Object[] paramArrayOfObject) throws Throwable {
- System.out.println("You are going to invoke "+paramMethod.getName()+" ...");
- paramMethod.invoke(car, null);
- System.out.println(paramMethod.getName()+" invocation Has Been finished...");
- return null;
- }
- }
生成動態代理類的字節碼并且保存到硬盤中:
JDK提供了sun.misc.ProxyGenerator.generateProxyClass(String proxyName,class[] interfaces) 底層方法來產生動態代理類的字節碼:
下面定義了一個工具類,用來將生成的動態代理類保存到硬盤中:
現在我們想將生成的代理類起名為“ElectricCarProxy”,并保存在硬盤,應該使用以下語句:
- package com.foo.proxy;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.lang.reflect.Proxy;
- import sun.misc.ProxyGenerator;
- public class ProxyUtils {
- /*
- * 將根據類信息 動態生成的二進制字節碼保存到硬盤中,
- * 默認的是clazz目錄下
- * params :clazz 需要生成動態代理類的類
- * proxyName : 為動態生成的代理類的名稱
- */
- public static void generateClassFile(Class clazz,String proxyName)
- {
- //根據類信息和提供的代理類名稱,生成字節碼
- byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
- String paths = clazz.getResource(".").getPath();
- System.out.println(paths);
- FileOutputStream out = null;
- try {
- //保留到硬盤中
- out = new FileOutputStream(paths+proxyName+".class");
- out.write(classFile);
- out.flush();
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- out.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
這樣將在ElectricCar.class 同級目錄下產生 ElectricCarProxy.class文件。用反編譯工具如jd-gui.exe 打開,將會看到以下信息:
- ProxyUtils.generateClassFile(car.getClass(), "ElectricCarProxy");
- import com.foo.proxy.Rechargable;
- import com.foo.proxy.Vehicle;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- import java.lang.reflect.UndeclaredThrowableException;
- /**
- 生成的動態代理類的組織模式是繼承Proxy類,然后實現需要實現代理的類上的所有接口,而在實現的過程中,則是通過將所有的方法都交給了InvocationHandler來處理
- */
- public final class ElectricCarProxy extends Proxy
- implements Rechargable, Vehicle
- {
- private static Method m1;
- private static Method m3;
- private static Method m4;
- private static Method m0;
- private static Method m2;
- public ElectricCarProxy(InvocationHandler paramInvocationHandler)
- throws
- {
- super(paramInvocationHandler);
- }
- public final boolean equals(Object paramObject)
- throws
- {
- try
- { // 方法功能實現交給InvocationHandler處理
- return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
- }
- catch (Error|RuntimeException localError)
- {
- throw localError;
- }
- catch (Throwable localThrowable)
- {
- throw new UndeclaredThrowableException(localThrowable);
- }
- }
- public final void recharge()
- throws
- {
- try
- {
- // 方法功能實現交給InvocationHandler處理
- this.h.invoke(this, m3, null);
- return;
- }
- catch (Error|RuntimeException localError)
- {
- throw localError;
- }
- catch (Throwable localThrowable)
- {
- throw new UndeclaredThrowableException(localThrowable);
- }
- }
- public final void drive()
- throws
- {
- try
- {
- // 方法功能實現交給InvocationHandler處理
- this.h.invoke(this, m4, null);
- return;
- }
- catch (Error|RuntimeException localError)
- {
- throw localError;
- }
- catch (Throwable localThrowable)
- {
- throw new UndeclaredThrowableException(localThrowable);
- }
- }
- public final int hashCode()
- throws
- {
- try
- {
- // 方法功能實現交給InvocationHandler處理
- return ((Integer)this.h.invoke(this, m0, null)).intValue();
- }
- catch (Error|RuntimeException localError)
- {
- throw localError;
- }
- catch (Throwable localThrowable)
- {
- throw new UndeclaredThrowableException(localThrowable);
- }
- }
- public final String toString()
- throws
- {
- try
- {
- // 方法功能實現交給InvocationHandler處理
- return (String)this.h.invoke(this, m2, null);
- }
- catch (Error|RuntimeException localError)
- {
- throw localError;
- }
- catch (Throwable localThrowable)
- {
- throw new UndeclaredThrowableException(localThrowable);
- }
- }
- static
- {
- try
- { //為每一個需要方法對象,當調用相應的方法時,分別將方法對象作為參數傳遞給InvocationHandler處理
- m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
- m3 = Class.forName("com.foo.proxy.Rechargable").getMethod("recharge", new Class[0]);
- m4 = Class.forName("com.foo.proxy.Vehicle").getMethod("drive", new Class[0]);
- m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
- m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
- return;
- }
- catch (NoSuchMethodException localNoSuchMethodException)
- {
- throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
- }
- catch (ClassNotFoundException localClassNotFoundException)
- {
- throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
- }
- }
- }
仔細觀察可以看出生成的動態代理類有以下特點:1.繼承自 java.lang.reflect.Proxy,實現了 Rechargable,Vehicle 這兩個ElectricCar實現的接口;
2.類中的所有方法都是final 的;
3.所有的方法功能的實現都統一調用了InvocationHandler的invoke()方法。
JDK中提供的生成動態代理類的機制有個鮮明的特點是: 某個類必須有實現的接口,而生成的代理類也只能代理某個類接口定義的方法,比如:如果上面例子的ElectricCar實現了繼承自兩個接口的方法外,另外實現了方法bee() ,則在產生的動態代理類中不會有這個方法了!更極端的情況是:如果某個類沒有實現接口,那么這個類就不能同JDK產生動態代理了!
幸好我們有cglib?!癈GLIB(Code Generation Library),是一個強大的,高性能,高質量的Code生成類庫,它可以在運行期擴展Java類與實現Java接口。”
cglib 創建某個類A的動態代理類的模式是:
1. 查找A上的所有非final 的public類型的方法定義;
2. 將這些方法的定義轉換成字節碼;
3. 將組成的字節碼轉換成相應的代理的class對象;
4. 實現 MethodInterceptor接口,用來處理 對代理類上所有方法的請求(這個接口和JDK動態代理InvocationHandler的功能和角色是一樣的)
一個有趣的例子:定義一個Programmer類,一個Hacker類
- package samples;
- /**
- * 程序猿類
- * @author louluan
- */
- public class Programmer {
- public void code()
- {
- System.out.println("I'm a Programmer,Just Coding.....");
- }
- }
- package samples;
- import java.lang.reflect.Method;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
- /*
- * 實現了方法攔截器接口
- */
- public class Hacker implements MethodInterceptor {
- @Override
- public Object intercept(Object obj, Method method, Object[] args,
- MethodProxy proxy) throws Throwable {
- System.out.println("**** I am a hacker,Let's see what the poor programmer is doing Now...");
- proxy.invokeSuper(obj, args);
- System.out.println("**** Oh,what a poor programmer.....");
- return null;
- }
- }
程序執行結果:
- package samples;
- import net.sf.cglib.proxy.Enhancer;
- public class Test {
- public static void main(String[] args) {
- Programmer progammer = new Programmer();
- Hacker hacker = new Hacker();
- //cglib 中加強器,用來創建動態代理
- Enhancer enhancer = new Enhancer();
- //設置要創建動態代理的類
- enhancer.setSuperclass(progammer.getClass());
- // 設置回調,這里相當于是對于代理類上所有方法的調用,都會調用CallBack,而Callback則需要實行intercept()方法進行攔截
- enhancer.setCallback(hacker);
- Programmer proxy =(Programmer)enhancer.create();
- proxy.code();
- }
- }
讓我們看看通過cglib生成的class文件內容:
- package samples;
- import java.lang.reflect.Method;
- import net.sf.cglib.core.ReflectUtils;
- import net.sf.cglib.core.Signature;
- import net.sf.cglib.proxy.Callback;
- import net.sf.cglib.proxy.Factory;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
- public class Programmer$$EnhancerByCGLIB$$fa7aa2cd extends Programmer
- implements Factory
- {
- //......省略
- private MethodInterceptor CGLIB$CALLBACK_0; // Enchaner傳入的methodInterceptor
- // ....省略
- public final void code()
- {
- MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
- if (tmp4_1 == null)
- {
- tmp4_1;
- CGLIB$BIND_CALLBACKS(this);//若callback 不為空,則調用methodInterceptor 的intercept()方法
- }
- if (this.CGLIB$CALLBACK_0 != null)
- return;
- //如果沒有設置callback回調函數,則默認執行父類的方法
- super.code();
- }
- //....后續省略
- }
|
來自: hh3755 > 《hibernate》