动态代理
Posted Mr.袋鼠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态代理相关的知识,希望对你有一定的参考价值。
这是动态原理的第二篇,这里要讲述的是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行接着分析。(可能会有些跳跃性,因为有些地方无法一句句分析到,请谅解。写到这里为止,花了三个半小时,写过长的博客,也慢慢懂得前辈们优秀的文章中是包含了好多的心血,读起来,去理解消化也绝非是一蹴而就的事情。)
b1 = this.firstInstance(e);
这一行调用了firstInstance方法,它是一个模板方法(空方法),在Enhancer类中实现了方法
1 protected Object firstInstance(Class type) throws Exception {
// 在前文create方法中,将classOnly设置为false,因此进入到后面的分支
// 建议简单的东西可以写三元运算符,复杂的东西不要用三元,因为一是容易出错,二是debug不方便 2 return this.classOnly ? type : this.createUsingReflection(type); 3 }
用反射创建实例,下面代码比较简单,大部分看名字就能知道其作用,我们着重看一下setThreadCallbacks方法,这里为了设置回调方法
1 private Object createUsingReflection(Class type) { 2 setThreadCallbacks(type, this.callbacks); 3 4 Object arg1; 5 try { 6 if (this.argumentTypes != null) { 7 arg1 = ReflectUtils.newInstance(type, this.argumentTypes, this.arguments); 8 return arg1; 9 } 10 11 arg1 = ReflectUtils.newInstance(type); 12 } finally { 13 setThreadCallbacks(type, (Callback[]) null); 14 } 15 16 return arg1; 17 }
1 private static void setThreadCallbacks(Class type, Callback[] callbacks) { 2 setCallbacksHelper(type, callbacks, "CGLIB$SET_THREAD_CALLBACKS"); 3 } 4 5 6 private static void setCallbacksHelper(Class type, Callback[] callbacks, String methodName) { 7 try { 8 Method e = getCallbacksSetter(type, methodName); 9 e.invoke((Object) null, new Object[]{callbacks}); 10 } catch (NoSuchMethodException arg3) { 11 throw new IllegalArgumentException(type + " is not an enhanced class"); 12 } catch (IllegalAccessException arg4) { 13 throw new CodeGenerationException(arg4); 14 } catch (InvocationTargetException arg5) { 15 throw new CodeGenerationException(arg5); 16 } 17 }
这个方法中的内容,不明白,如果有明白的朋友,请您告诉我。!!!
1 private static Method getCallbacksSetter(Class type, String methodName) throws NoSuchMethodException { 2 return type 3 .getDeclaredMethod(methodName, 4 new Class[]{array$Lnet$sf$cglib$proxy$Callback == null 5 ? (array$Lnet$sf$cglib$proxy$Callback = class$( 6 "[Lorg.springframework.cglib.proxy.Callback;")) 7 : array$Lnet$sf$cglib$proxy$Callback}); 8 }
暂且写到这里了,自己感觉后部分,有许多东西,写的不透彻,原因是自己也没有百分百理解好,导致了这个现象,惭愧!!!
继续努力,fighting!!!
以上是关于动态代理的主要内容,如果未能解决你的问题,请参考以下文章