動態代理(二)
這是動態原理的第二篇,這裏要講述的是Cglib的東東。接下來,進正題。
參考文章:http://www.cnblogs.com/cruze/p/3843996.html
一、Cglib
CGLIB是一個功能強大,高性能的代碼生成包。它為沒有實現接口的類提供代理,為JDK的動態代理提供了很好的補充。通常可以使用Java的動態代理創建代理,但當要代理的類沒有實現接口或者為了更好的性能,CGLIB是一個好的選擇。
二、Cglib原理
動態生成一個要代理類的子類,子類重寫要代理的類的所有不是final的方法。在子類中采用方法攔截的技術攔截所有父類方法的調用,順勢織入橫切邏輯。它比使用java反射的JDK動態代理要快。
三、實例分析
分析前,我用一句話來概括Cglib的過程。首先將被代理類TargetObject設置成父類,然後設置攔截器TargetInterceptor,最後執行enhancer.create()動態生成一個代理類,並從Object強制轉型成父類型TargetObject。
1.demo(註:示例代碼我是從別的地方copy過來的,哪裏來的我把地址忘了,所以沒有貼上連接。但是後面的源碼分析的部分,是自己一點點分析記錄的。)
1 package com.lee.demo.springSourceLearn.demo; 2 3 public class BookEditImpl { 4 publicvoid addBook() { 5 System.out.println("add Book..."); 6 } 7 }
1 import java.lang.reflect.Method; 2 3 import org.springframework.cglib.proxy.Enhancer; 4 import org.springframework.cglib.proxy.MethodInterceptor; 5 import org.springframework.cglib.proxy.MethodProxy; 6 7 publicclass BookFacadeCglib implements MethodInterceptor { 8 private Object target;//業務類對象,供代理方法中進行真正的業務方法調用 9 10 //相當於JDK動態代理中的綁定 11 public Object getInstance(Object target) { 12 this.target = target; //給業務對象賦值 13 Enhancer enhancer = new Enhancer(); //創建加強器,用來創建動態代理類 14 enhancer.setSuperclass(this.target.getClass()); //為加強器指定要代理的業務類(即:為下面生成的代理類指定父類) 15 //設置回調:對於代理類上所有方法的調用,都會調用CallBack,而Callback則需要實現intercept()方法進行攔 16 enhancer.setCallback(this); 17 // 創建動態代理類對象並返回 18 return enhancer.create(); 19 } 20 // 實現回調方法 21 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 22 System.out.println("預處理——————"); 23 proxy.invokeSuper(obj, args); //調用業務類(父類中)的方法 24 System.out.println("調用後操作——————"); 25 return null; 26 } 27 }
1 public class Test02 { 2 3 public static void main(String[] args) {
// 生成的class文件默認只存儲在內存中,我們可以在代碼中加入下面語句來獲取class file
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:\\Users\\lihao\\git"); 4 BookEditImpl bookFacade=new BookEditImpl(); 5 BookFacadeCglib cglib=new BookFacadeCglib(); 6 BookEditImpl bookCglib=(BookEditImpl)cglib.getInstance(bookFacade); 7 bookCglib.addBook(); 8 } 9 }
運行執行結果如下:
預處理——————
add Book...
調用後操作——————
2.過程分析
首先getInstance中會先進行父類和回調方法的設置,接下來,進入enhancer.create的方法。
1 public Object create() {
// 下面兩行暫時不知道屬性的作用,暫且放下,進入方法繼續探索 2 this.classOnly = false; 3 this.argumentTypes = null; 4 return this.createHelper(); 5 }
1 private Object createHelper() {
// 進行有效性驗證,比如有多個callBack卻沒有callBackFilter
2 this.validate();
3 if (this.superclass != null) {
// 前面已經設置了superClass,所以會進到這個分支裏來
4 this.setNamePrefix(this.superclass.getName());
5 } else if (this.interfaces != null) {
6 this.setNamePrefix(this.interfaces[ReflectUtils.findPackageProtected(this.interfaces)].getName());
7 }
8
// KEY_FACTORY根據代理類的組合信息,生成一個組合key,這個key用在後面的緩存的地方
// 為什麽會用到緩存呢? 因為我們調用一個類中的某個方法,就會生成一個代理類,再調用類的另一個方法時,代理類已經存在了,就不要再重復創建了,因此便有了緩存的想法。
// 父類: public class Enhancer extends AbstractClassGenerator
9 return super.create(KEY_FACTORY.newInstance(this.superclass != null ? this.superclass.getName() : null,
10 ReflectUtils.getNames(this.interfaces), this.filter, this.callbackTypes, this.useFactory,
11 this.interceptDuringConstruction, this.serialVersionUID));
12 }
1 protected Object create(Object key) { 2 try { 3 Class e = null; 4 Source arg2 = this.source; 5 synchronized (this.source) {
// 生成類的緩存是按照ClassLoader來區分的,因為類的區分是按照類名和ClassLoader兩者組合來區分的,同樣的類名,不同的ClassLodaer,那麽類也是不同的 6 ClassLoader loader = this.getClassLoader(); 7 Object cache2 = null;
// cache數據結構 Map<ClassLaodaer,Map<nameKey,HashSet>> 8 cache2 = (Map) this.source.cache.get(loader); 9 if (cache2 == null) { 10 cache2 = new HashMap(); 11 ((Map) cache2).put(NAME_KEY, new HashSet()); 12 this.source.cache.put(loader, cache2); 13 } else if (this.useCache) { 14 Reference save = (Reference) ((Map) cache2).get(key); 15 e = (Class) (save == null ? null : save.get()); 16 } 17 18 if (e == null) { 19 Object save1 = CURRENT.get(); 20 CURRENT.set(this); 21 22 Object b1; 23 try { 24 this.key = key;
// debug的時候發現這個attemptLoad值為false,就不會進入這個分支,接下來進入到e=null裏面 25 if (this.attemptLoad) { 26 try { 27 e = loader.loadClass(this.getClassName()); 28 } catch (ClassNotFoundException arg16) { 29 ; 30 } 31 } 32 33 if (e == null) {
// 代理類生成的操作,使用相應的策略生成34 byte[] b = this.strategy.generate(this); 35 String className = ClassNameReader.getClassName(new ClassReader(b)); 36 this.getClassNameCache(loader).add(className); 37 e = ReflectUtils.defineClass(className, b, loader); 38 } 39 40 if (this.useCache) { 41 ((Map) cache2).put(key, new WeakReference(e)); 42 } 43 44 b1 = this.firstInstance(e); 45 } finally { 46 CURRENT.set(save1); 47 } 48 49 return b1; 50 } 51 } 52 53 return this.firstInstance(e); 54 } catch (RuntimeException arg19) { 55 throw arg19; 56 } catch (Error arg20) { 57 throw arg20; 58 } catch (Exception arg21) { 59 throw new CodeGenerationException(arg21); 60 } 61 }
下面代碼一共三行,但是東西是真心不少啊!一行行分析。有時代碼越少,越難
1 public byte[] generate(ClassGenerator cg) throws Exception { 2 DebuggingClassWriter cw = this.getClassVisitor(); 3 this.transform(cg).generateClass(cw); 4 return this.transform(cw.toByteArray()); 5 }
getClassVisitor
1 protected DebuggingClassWriter getClassVisitor() throws Exception { 2 return new DebuggingClassWriter(1); 3 }
DebuggingClassWriter 關註下面標紅的部分
1 public class DebuggingClassWriter extends ClassVisitor { 2 public static final String DEBUG_LOCATION_PROPERTY = "cglib.debugLocation"; 3 private static String debugLocation = System.getProperty("cglib.debugLocation"); 4 private static Constructor traceCtor; 5 private String className; 6 private String superName; 7 8 public DebuggingClassWriter(int flags) { 9 super(262144, new ClassWriter(flags)); 10 } 11 12 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 13 this.className = name.replace(‘/‘, ‘.‘); 14 this.superName = superName.replace(‘/‘, ‘.‘); 15 super.visit(version, access, name, signature, superName, interfaces); 16 } 17 18 public String getClassName() { 19 return this.className; 20 } 21 22 public String getSuperName() { 23 return this.superName; 24 } 25 26 public byte[] toByteArray() { 27 return (byte[])((byte[])AccessController.doPrivileged(new 1(this))); 28 } 29 30 static {
// 通過這裏就能知道,如何生成CGLIB動態代理類到本地 31 if (debugLocation != null) { 32 System.err.println("CGLIB debugging enabled, writing to \‘" + debugLocation + "\‘"); 33 34 try { 35 Class ignore = Class.forName("org.springframework.asm.util.TraceClassVisitor"); 36 traceCtor = ignore 37 .getConstructor(new Class[]{ 38 class$org$objectweb$asm$ClassVisitor == null 39 ? (class$org$objectweb$asm$ClassVisitor = class$( 40 "org.springframework.asm.ClassVisitor")) 41 : class$org$objectweb$asm$ClassVisitor, 42 class$java$io$PrintWriter == null 43 ? (class$java$io$PrintWriter = class$("java.io.PrintWriter")) 44 : class$java$io$PrintWriter}); 45 } catch (Throwable arg0) { 46 ; 47 } 48 } 49 50 } 51 }
回到generate方法,
1 protected ClassGenerator transform(ClassGenerator cg) throws Exception { 2 return cg; 3 }
1 public interface ClassGenerator { 2 void generateClass(ClassVisitor arg0) throws Exception; 3 }
那麽,generateClass的實現類的方法是哪個呢?
public class Enhancer extends AbstractClassGenerator
public abstract class AbstractClassGenerator implements ClassGenerator
最後回歸到Enhancer這個類中。。。
我們接下來回到上文create方法中的44行接著分析。(可能會有些跳躍性,因為有些地方無法一句句分析到,請諒解。寫到這裏為止,花了三個半小時,寫過長的博客,也慢慢懂得前輩們優秀的文章中是包含了好多的心血,讀起來,去理解消化也絕非是一蹴而就的事情。)
未完待續。。。
CGLIB是一個功能強大,高性能的代碼生成包。它為沒有實現接口的類提供代理,為JDK的動態代理提供了很好的補充。通常可以使用Java的動態代理創建代理,但當要代理的類沒有實現接口或者為了更好的性能,CGLIB是一個好的選擇。
動態代理(二)