1. 程式人生 > >動態代理(二)

動態代理(二)

object throws classname 什麽 ace mep sets finall 源碼分析

這是動態原理的第二篇,這裏要講述的是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     public
void 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 public
class 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是一個好的選擇。

動態代理(二)