JAVA代理源码详解,手把手教你写JAVA代理
一:常用的java代理模式
一般经常做java开发的知道java的代理模式一共有三种,第一种也就是静态代理,这种用法比较简单,没有什么魔法棒,比较好理解,另外两种分别是JDK代理和cglib代理,他们分别是对接口代理和对class类本身进行代理,jdk代理要求类必须实现有一个或者多个接口,对接口进行字节码增强在内存中实现新的class类去反射调用用户target的实现类,这里需要说明的是不管是cglic代理也好还是jdk代理他们在内存中都要占据方法区资源(jdk8 叫原空间),从而达到代理目的,而cglib代理是对class类本身进行字节码增强配合fastclass来实现代理,关于更多的cglib和jdk代理相关的内容大家可以google搜索一下,网上有很多这里不做再多的说明。下面我们摒弃jdk,和cglib的复杂源码来自己实现一个代理模式,来更深刻的了解一下代理究竟是怎么形成的。
二:JDK代理源码分析
②被代理类实现业务接口;
③定义代理类并实现业务接口;
④最后便可通过客户端进行调用。(这里可以理解成程序的main方法里的内容)
我们按照这个步骤去实现静态代理。需求:在向数据库添加一个用户时前后打印日志。
public interface IUserService { void add(String name); }
UserServiceImpl.java
public class UserServiceImpl implements IUserService{ @Override public void add(String name) { System.out.println("数据库中插入: "+name+" 的用户"); } }
MyInvocationHandler.java
public class MyInvocationHandler implements InvocationHandler { //被代理对象,Object类型 private Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("准备向数据库中插入数据"); Object returnvalue = method.invoke(target, args); System.out.println("插入数据库成功"); return returnvalue; } }
测试类
public static void main(String[] args) { IUserService target = new UserServiceImpl(); MyInvocationHandler handler = new MyInvocationHandler(target); IUserService proxyObject = (IUserService) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(), target.getClass().getInterfaces(), handler); proxyObject.add("张玉龙"); }
使用上非常简单、网上demo也很多,不做充分讲解,对jdk代理用法的小伙伴如果还不熟悉这块代码,就先了解一下jdk代理的使用方式,然后在回来继续看下面的源码分析
JDK代理源码深度分析
Proxy.newProxyInstance( ClassLoaderloader, Class[] interfaces, InvocationHandler h)
产生了代理对象,所以我们进到newProxyInstance
的实现:public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }
getProxyClass0(loader, intfs)
得到代理类的Class对象,然后通过Class对象得到构造方法,进而创建代理对象。下一步看getProxyClass0
这个方法。//此方法也是Proxy类下的方法 private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // If the proxy class defined by the given loader implementing // the given interfaces exists, this will simply return the cached copy; // otherwise, it will create the proxy class via the ProxyClassFactory //意思是:如果代理类被指定的类加载器loader定义了,并实现了给定的接口interfaces, //那么就返回缓存的代理类对象,否则使用ProxyClassFactory创建代理类。 return proxyClassCache.get(loader, interfaces); }
这里看到proxyClassCache,有Cache便知道是缓存的意思,正好呼应了前面Look up or generate the designated proxy class。查询(在缓存中已经有)或生成指定的代理类的class对象这段注释。
proxyClassCache
是个WeakCache类的对象,调用proxyClassCache.get(loader, interfaces); 可以得到缓存的代理类或创建代理类(没有缓存的情况)。说明WeakCache中有get
这个方法。先看下WeakCache类的定义(这里先只给出变量的定义和构造函数):
//K代表key的类型,P代表参数的类型,V代表value的类型。 // WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache 说明proxyClassCache存的值是Class<?>对象,正是我们需要的代理类对象。 final class WeakCache<K, P, V> { private final ReferenceQueue<K> refQueue = new ReferenceQueue<>(); // the key type is Object for supporting null key private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map = new ConcurrentHashMap<>(); private final ConcurrentMap<Supplier<V>, Boolean> reverseMap = new ConcurrentHashMap<>(); private final BiFunction<K, P, ?> subKeyFactory; private final BiFunction<K, P, V> valueFactory; public WeakCache(BiFunction<K, P, ?> subKeyFactory, BiFunction<K, P, V> valueFactory) { this.subKeyFactory = Objects.requireNonNull(subKeyFactory); this.valueFactory = Objects.requireNonNull(valueFactory); }
(key, sub-key) -> value
。其中key是传进来的Classloader进行包装后的对象,sub-key是由WeakCache构造函数传人的KeyFactory()
生成的。value就是产生代理类的对象,是由WeakCache构造函数传人的ProxyClassFactory()
生成的好,大体上说完WeakCache这个类的作用,我们回到刚才
proxyClassCache.get(loader, interfaces);
这句代码。get是WeakCache里的方法。源码如下//K和P就是WeakCache定义中的泛型,key是类加载器,parameter是接口类数组 public V get(K key, P parameter) { //检查parameter不为空 Objects.requireNonNull(parameter); //清除无效的缓存 expungeStaleEntries(); // cacheKey就是(key, sub-key) -> value里的一级key, Object cacheKey = CacheKey.valueOf(key, refQueue); // lazily install the 2nd level valuesMap for the particular cacheKey //根据一级key得到 ConcurrentMap<Object, Supplier<V>>对象。如果之前不存在,则新建一个ConcurrentMap<Object, Supplier<V>>和cacheKey(一级key)一起放到map中。 ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); if (valuesMap == null) { ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>()); if (oldValuesMap != null) { valuesMap = oldValuesMap; } } // create subKey and retrieve the possible Supplier<V> stored by that // subKey from valuesMap //这部分就是调用生成sub-key的代码,上面我们已经看过怎么生成的了 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); //通过sub-key得到supplier Supplier<V> supplier = valuesMap.get(subKey); //supplier实际上就是这个factory Factory factory = null; while (true) { //如果缓存里有supplier ,那就直接通过get方法,得到代理类对象,返回,就结束了,一会儿分析get方法。 if (supplier != null) { // supplier might be a Factory or a CacheValue<V> instance V value = supplier.get(); if (value != null) { return value; } } // else no supplier in cache // or a supplier that returned null (could be a cleared CacheValue // or a Factory that wasn't successful in installing the CacheValue) // lazily construct a Factory //下面的所有代码目的就是:如果缓存中没有supplier,则创建一个Factory对象,把factory对象在多线程的环境下安全的赋给supplier。 //因为是在while(true)中,赋值成功后又回到上面去调get方法,返回才结束。 if (factory == null) { factory = new Factory(key, parameter, subKey, valuesMap); } if (supplier == null) { supplier = valuesMap.putIfAbsent(subKey, factory); if (supplier == null) { // successfully installed Factory supplier = factory; } // else retry with winning supplier } else { if (valuesMap.replace(subKey, supplier, factory)) { // successfully replaced // cleared CacheEntry / unsuccessful Factory // with our Factory supplier = factory; } else { // retry with current supplier supplier = valuesMap.get(subKey); } } } }
所以接下来我们看Factory类中的get方法。
public synchronized V get() { // serialize access // re-check Supplier<V> supplier = valuesMap.get(subKey); //重新检查得到的supplier是不是当前对象 if (supplier != this) { // something changed while we were waiting: // might be that we were replaced by a CacheValue // or were removed because of failure -> // return null to signal WeakCache.get() to retry // the loop return null; } // else still us (supplier == this) // create new value V value = null; try { //代理类就是在这个位置调用valueFactory生成的 //valueFactory就是我们传入的 new ProxyClassFactory() //一会我们分析ProxyClassFactory()的apply方法 value = Objects.requireNonNull(valueFactory.apply(key, parameter)); } finally { if (value == null) { // remove us on failure valuesMap.remove(subKey, this); } } // the only path to reach here is with non-null value assert value != null; // wrap value with CacheValue (WeakReference) //把value包装成弱引用 CacheValue<V> cacheValue = new CacheValue<>(value); // put into reverseMap // reverseMap是用来实现缓存的有效性 reverseMap.put(cacheValue, Boolean.TRUE); // try replacing us with CacheValue (this should always succeed) if (!valuesMap.replace(subKey, this, cacheValue)) { throw new AssertionError("Should not reach here"); } // successfully replaced us with new CacheValue -> return the value // wrapped by it return value; } }
拨云见日,来到ProxyClassFactory的apply方法,代理类就是在这里生成的。
//这里的BiFunction<T, U, R>是个函数式接口,可以理解为用T,U两种类型做参数,得到R类型的返回值 private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { // prefix for all proxy class names //所有代理类名字的前缀 private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names //用于生成代理类名字的计数器 private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); //验证代理接口,可不看 for (Class<?> intf : interfaces) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ Class<?> interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != intf) { throw new IllegalArgumentException( intf + " is not visible from class loader"); } /* * Verify that the Class object actually represents an * interface. */ if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } /* * Verify that this interface is not a duplicate. */ if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } //生成的代理类的包名 String proxyPkg = null; // package to define proxy class in //代理类访问控制符: public ,final int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same package. */ //验证所有非公共的接口在同一个包内;公共的就无需处理 //生成包名和类名的逻辑,包名默认是com.sun.proxy,类名默认是$Proxy 加上一个自增的整数值 //如果被代理类是 non-public proxy interface ,则用和被代理类接口一样的包名 for (Class<?> intf : interfaces) { int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) { accessFlags = Modifier.FINAL; String name = intf.getName(); int n = name.lastIndexOf('.'); String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); if (proxyPkg == null) { proxyPkg = pkg; } else if (!pkg.equals(proxyPkg)) { throw new IllegalArgumentException( "non-public interfaces from different packages"); } } } if (proxyPkg == null) { // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); //代理类的完全限定名,如com.sun.proxy.$Proxy0.calss String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ //核心部分,生成代理类的字节码 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { //把代理类加载到JVM中,至此动态代理过程基本结束了 return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /* * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new IllegalArgumentException(e.toString()); } } }
到这里其实已经分析完了,但是本着深究的态度,决定看看JDK生成的动态代理字节码是什么,于是我们将字节码保存到磁盘上的class文件中。代码如下:
public static void main(String[] args) { IUserService target = new UserServiceImpl(); MyInvocationHandler handler = new MyInvocationHandler(target); //第一个参数是指定代理类的类加载器(我们传入当前测试类的类加载器) //第二个参数是代理类需要实现的接口(我们传入被代理类实现的接口,这样生成的代理类和被代理类就实现了相同的接口) //第三个参数是invocation handler,用来处理方法的调用。这里传入我们自己实现的handler IUserService proxyObject = (IUserService) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(), target.getClass().getInterfaces(), handler); proxyObject.add("张玉龙"); String path = "D:/$Proxy0.class"; byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", HelloworldImpl.class.getInterfaces()); FileOutputStream out = null; try { out = new FileOutputStream(path); out.write(classFile); out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } }
运行这段代码,会在D盘生成一个名为$Proxy0.class的文件。通过反编译工具,得到JDK为我们生成的代理类是这样的:
// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov. // Jad home page: http://kpdus.tripod.com/jad.html // Decompiler options: packimports(3) fieldsfirst ansi space import com.zhb.jdk.proxy.IUserService; import java.lang.reflect.*; public final class $Proxy0 extends Proxy implements IUserService { private static Method m1; private static Method m2; private static Method m3; private static Method m0; //代理类的构造函数,其参数正是是InvocationHandler实例, //Proxy.newInstance方法就是通过通过这个构造函数来创建代理实例的 public $Proxy0(InvocationHandler invocationhandler) { super(invocationhandler); } // Object类中的三个方法,equals,toString, hashCode public final boolean equals(Object obj) { try { return ((Boolean)super.h.invoke(this, m1, new Object[] { obj })).booleanValue(); } catch (Error ) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final String toString() { try { return (String)super.h.invoke(this, m2, null); } catch (Error ) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } //接口代理方法 public final void add(String s) { try { // invocation handler的 invoke方法在这里被调用 super.h.invoke(this, m3, new Object[] { s }); return; } catch (Error ) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final int hashCode() { try { // 在这里调用了invoke方法。 return ((Integer)super.h.invoke(this, m0, null)).intValue(); } catch (Error ) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } // 静态代码块对变量进行一些初始化工作 static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m3 = Class.forName("com.zhb.jdk.proxy.IUserService").getMethod("add", new Class[] { Class.forName("java.lang.String") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); } catch (NoSuchMethodException nosuchmethodexception) { throw new NoSuchMethodError(nosuchmethodexception.getMessage()); } catch (ClassNotFoundException classnotfoundexception) { throw new NoClassDefFoundError(classnotfoundexception.getMessage()); } } }
生成了Object类的三个方法:toString,hashCode,equals。还有我们需要被代理的方法。
JDK代理类的cache clear机制
大家都知道、在项目中被代理的class越来越多,所以jdk会搞一个cache的方式来防止相同的代理接口重复生成class,影响性能不说,实现也不是很优雅,那么现在就会有一个问题了,当classloader已经在内存中没有依赖的时候,被代理的proxy class其实也没有什么意义了,这样就需要清空无用的cache,java Proxy采用了非常巧妙的“弱引用机制”,我们来看下面的代码
我们还是继续看get方法的源码
public V get(K key, P parameter) { Objects.requireNonNull(parameter); expungeStaleEntries(); Object cacheKey = CacheKey.valueOf(key, refQueue); // lazily install the 2nd level valuesMap for the particular cacheKey ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); if (valuesMap == null) { ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>()); if (oldValuesMap != null) { valuesMap = oldValuesMap; } } ....... }
其中源码中有一个方法expungeStaleEntries、我们进去这个方法一窥究竟
private void expungeStaleEntries() { CacheKey<K> cacheKey; while ((cacheKey = (CacheKey<K>)refQueue.poll()) != null) { cacheKey.expungeFrom(map, reverseMap); } }
在看看expungeFrom方法源码干了些什么
void expungeFrom(ConcurrentMap<?, ? extends ConcurrentMap<?, ?>> map, ConcurrentMap<?, Boolean> reverseMap) { // removing just by key is always safe here because after a CacheKey // is cleared and enqueue-ed it is only equal to itself // (see equals method)... ConcurrentMap<?, ?> valuesMap = map.remove(this); // remove also from reverseMap if needed if (valuesMap != null) { for (Object cacheValue : valuesMap.values()) { reverseMap.remove(cacheValue); } } }
代码很清晰了,清空被代理的对象。现在的关键就是refQueue对象是怎么来的。我们继续找一下跟refQueue相关的源码、在get中还有一段代码是这样的
Object cacheKey = CacheKey.valueOf(key, refQueue);
private static final class CacheKey<K> extends WeakReference<K> { // a replacement for null keys private static final Object NULL_KEY = new Object(); static <K> Object valueOf(K key, ReferenceQueue<K> refQueue) { return key == null // null key means we can't weakly reference it, // so we use a NULL_KEY singleton as cache key ? NULL_KEY // non-null key requires wrapping with a WeakReference : new CacheKey<>(key, refQueue); } private final int hash; private CacheKey(K key, ReferenceQueue<K> refQueue) { super(key, refQueue); this.hash = System.identityHashCode(key); // compare by identity } ..... }
这样看就非常清晰了、原来是CacheKey继承了WeakReference弱引用机制,当弱引用依赖的key没有引用的时候,当前失效的对象就会进入ReferenceQueue中来实现清空cache的功能、这种实现思路和ThreadLocal的实现原理是一样的、大家有兴趣可以去阅读以下相关源码。
三:cglib代理源码分析
有了上面的源码分析经验,聪明的小伙伴一定知道cglib代理实际上也差不多,只不过是基于Class类生成的,可以对类进行代理,无需接口,但是内部的实验逻辑也比较复杂,先上一个简单的demo
package cglib; import net.sf.cglib.core.DebuggingClassWriter; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CglibTest implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println ("我被代理了"); return proxy.invokeSuper ( obj,args ); } public String hello(String name){ return "你好" + name; } public static void main(String[] args) { System.setProperty ( DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/zhangyulong/Downloads" ); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass (CglibTest.class); enhancer.setCallback(new CglibTest()); CglibTest cglibTest = (CglibTest) enhancer.create (); String result = cglibTest.hello ( "张玉龙" ); System.out.println (result); } }
执行结果
CGLIB debugging enabled, writing to '/Users/zhangyulong/Downloads' 我被代理了 你好张玉龙
”耳熟能详“的生成结果,那么接下来我们看看它到底是怎么生成的,实现原理和Jdk代理有什么不同?
我们一层一层的翻源码来看看
public Object create() { classOnly = false; argumentTypes = null; return createHelper(); }
classOnly代码是否只生成class,不生成代理对象,默认是false,说明要生成对象。argumentType是构造器参数类型,由于我们使用无参构造器,这些参数暂时可以忽略掉。
private Object createHelper() { preValidate(); Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null, ReflectUtils.getNames(interfaces), filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter), callbackTypes, useFactory, interceptDuringConstruction, serialVersionUID); this.currentKey = key; Object result = super.create(key); return result; }
preValidate 首先验证一下参数类型以及基础校验,cglib支持CallbackFilter,由于我们callBack只有一个,enhancer.setCallback(new CglibTest()); 所以这里默认没有filter,看下cglib的处理
private void preValidate() { if (callbackTypes == null) { callbackTypes = CallbackInfo.determineTypes(callbacks, false); validateCallbackTypes = true; } if (filter == null) { if (callbackTypes.length > 1) { throw new IllegalStateException("Multiple callback types possible but no filter specified"); } filter = ALL_ZERO; } }
private static final CallbackFilter ALL_ZERO = new CallbackFilter(){
public int accept(Method method) {
return 0;
}
};
默认返回0,就是我们传入的new CglibTest()。重新返回主流程,我们看一下
Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null, ReflectUtils.getNames(interfaces), filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter), callbackTypes, useFactory, interceptDuringConstruction, serialVersionUID); this.currentKey = key; Object result = super.create(key);
首先根据代理类生成了一个key。这个key的主要作用就是对生成的代理类进行缓存,生成代码在KeyFactory.create方法。这里不是主线流程,感兴趣的小伙伴自己深入一下即可
public static KeyFactory create(ClassLoader loader, Class keyInterface, KeyFactoryCustomizer customizer, List<KeyFactoryCustomizer> next) { Generator gen = new Generator(); gen.setInterface(keyInterface); if (customizer != null) { gen.addCustomizer(customizer); } if (next != null && !next.isEmpty()) { for (KeyFactoryCustomizer keyFactoryCustomizer : next) { gen.addCustomizer(keyFactoryCustomizer); } } gen.setClassLoader(loader); return gen.create(); }
我们主要看一下AbstractClassGenerator.create方法,这里也是我们生成代理代码的主流程
protected Object create(Object key) { try { ClassLoader loader = getClassLoader(); Map<ClassLoader, ClassLoaderData> cache = CACHE; ClassLoaderData data = cache.get(loader); if (data == null) { synchronized (AbstractClassGenerator.class) { cache = CACHE; data = cache.get(loader); if (data == null) { Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache); data = new ClassLoaderData(loader); newCache.put(loader, data); CACHE = newCache; } } } this.key = key; Object obj = data.get(this, getUseCache()); if (obj instanceof Class) { return firstInstance((Class) obj); } return nextInstance(obj); } catch (RuntimeException e) { throw e; } catch (Error e) { throw e; } catch (Exception e) { throw new CodeGenerationException(e); } }
聪明的小伙伴已经发现了,cglib代理以及jdk代理的缓存结构大同小异。
private static volatile Map<ClassLoader, ClassLoaderData> CACHE = new WeakHashMap<ClassLoader, ClassLoaderData>();
1级缓存, ClassLoader以及我们cglib的代理缓存对象ClassLoaderData,在ClassLoaderData里维护了一个弱引用的classloader对象,以及代理类的缓存对偶性 LoadingCache。这和JDK代理弱引用classloader几乎是完全一样的
public ClassLoaderData(ClassLoader classLoader) { if (classLoader == null) { throw new IllegalArgumentException("classLoader == null is not yet supported"); } this.classLoader = new WeakReference<ClassLoader>(classLoader); Function<AbstractClassGenerator, Object> load = new Function<AbstractClassGenerator, Object>() { public Object apply(AbstractClassGenerator gen) { Class klass = gen.generate(ClassLoaderData.this); return gen.wrapCachedClass(klass); } }; generatedClasses = new LoadingCache<AbstractClassGenerator, Object, Object>(GET_KEY, load); }
public ClassLoader getClassLoader() {
return classLoader.get();
}
上面我们讲了JDK代理的缓存清空的逻辑,那么我们看下cglib代理对象时,classloader失效后如何处理的,毕竟是弱引用classloader,那么一定要做缓存清空处理的。
ClassLoader classLoader = data.getClassLoader(); if (classLoader == null) { throw new IllegalStateException("ClassLoader is null while trying to define class " + getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " + "Please file an issue at cglib's issue tracker."); }
cglib的处理还是比较暴力的,直接抛出异常。接下来我们看下二级缓存以及生成字节码的处理
public Object get(AbstractClassGenerator gen, boolean useCache) { if (!useCache) { return gen.generate(ClassLoaderData.this); } else { Object cachedValue = generatedClasses.get(gen); return gen.unwrapCachedValue(cachedValue); } }
useCache来决定是否生成字节码后,每次都缓存。 我们手动设置就可以了。
/** * Whether use and update the static cache of generated classes * for a class with the same properties. Default is <code>true</code>. */ public void setUseCache(boolean useCache) { this.useCache = useCache; } /** * @see #setUseCache */ public boolean getUseCache() { return useCache; }
Object cachedValue = generatedClasses.get(gen); 缓存的逻辑分支,我们接着跟下去。
public V get(K key) { final KK cacheKey = keyMapper.apply(key); Object v = map.get(cacheKey); if (v != null && !(v instanceof FutureTask)) { return (V) v; } return createEntry(key, cacheKey, v); }
逻辑非常清晰了,先看map中是否有cache对象。有直接拿出来,没有通过createEntry(key, cacheKey, v)来生成即可。keyMapper.apply(key)是什么呢,我们看看
private static final Function<AbstractClassGenerator, Object> GET_KEY = new Function<AbstractClassGenerator, Object>() { public Object apply(AbstractClassGenerator gen) { return gen.key; } };
gen.key就是我们上面提到的KeyFactory生成的key。生成代理对象,并且缓存下来
protected V createEntry(final K key, KK cacheKey, Object v) { FutureTask<V> task; boolean creator = false; if (v != null) { // Another thread is already loading an instance task = (FutureTask<V>) v; } else { task = new FutureTask<V>(new Callable<V>() { public V call() throws Exception { return loader.apply(key); } }); Object prevTask = map.putIfAbsent(cacheKey, task); if (prevTask == null) { // creator does the load creator = true; task.run(); } else if (prevTask instanceof FutureTask) { task = (FutureTask<V>) prevTask; } else { return (V) prevTask; } } V result; try { result = task.get(); } catch (InterruptedException e) { throw new IllegalStateException("Interrupted while loading cache item", e); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof RuntimeException) { throw ((RuntimeException) cause); } throw new IllegalStateException("Unable to load cache item", cause); } if (creator) { map.put(cacheKey, result); } return result; }
到目前为止,我们缓存相关的逻辑都已经讲解完毕了,我们把精力放到生成字节码部分,最终生成字节码的方法如下
protected Class generate(ClassLoaderData data) { Class gen; Object save = CURRENT.get(); CURRENT.set(this); try { ClassLoader classLoader = data.getClassLoader(); if (classLoader == null) { throw new IllegalStateException("ClassLoader is null while trying to define class " + getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " + "Please file an issue at cglib's issue tracker."); } synchronized (classLoader) { String name = generateClassName(data.getUniqueNamePredicate()); data.reserveName(name); this.setClassName(name); } if (attemptLoad) { try { gen = classLoader.loadClass(getClassName()); return gen; } catch (ClassNotFoundException e) { // ignore } } byte[] b = strategy.generate(this); String className = ClassNameReader.getClassName(new ClassReader(b)); ProtectionDomain protectionDomain = getProtectionDomain(); synchronized (classLoader) { // just in case if (protectionDomain == null) { gen = ReflectUtils.defineClass(className, b, classLoader); } else { gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain); } } return gen; } catch (RuntimeException e) { throw e; } catch (Error e) { throw e; } catch (Exception e) { throw new CodeGenerationException(e); } finally { CURRENT.set(save); } }
先使用generateClassName生成代理类的名字,这里就是我们debug Spring Aop源码以及其他源码中 带$符号以及cglib很长的名称。
private String generateClassName(Predicate nameTestPredicate) { return namingPolicy.getClassName(namePrefix, source.name, key, nameTestPredicate); }
最关键的生成字节码的部分
byte[] b = strategy.generate(this); public byte[] generate(ClassGenerator cg) throws Exception { DebuggingClassWriter cw = getClassVisitor(); transform(cg).generateClass(cw); return transform(cw.toByteArray()); } protected DebuggingClassWriter getClassVisitor() throws Exception { return new DebuggingClassWriter(ClassWriter.COMPUTE_FRAMES); }
public byte[] toByteArray() { return (byte[]) java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Object run() { byte[] b = ((ClassWriter) DebuggingClassWriter.super.cv).toByteArray(); if (debugLocation != null) { String dirs = className.replace('.', File.separatorChar); try { new File(debugLocation + File.separatorChar + dirs).getParentFile().mkdirs(); File file = new File(new File(debugLocation), dirs + ".class"); OutputStream out = new BufferedOutputStream(new FileOutputStream(file)); try { out.write(b); } finally { out.close(); } if (traceCtor != null) { file = new File(new File(debugLocation), dirs + ".asm"); out = new BufferedOutputStream(new FileOutputStream(file)); try { ClassReader cr = new ClassReader(b); PrintWriter pw = new PrintWriter(new OutputStreamWriter(out)); ClassVisitor tcv = (ClassVisitor)traceCtor.newInstance(new Object[]{null, pw}); cr.accept(tcv, 0); pw.flush(); } finally { out.close(); } } } catch (Exception e) { throw new CodeGenerationException(e); } } return b; } }); } }
我们看到这里可以将生成的代码放到指定的位置来方便查看。这也就是我们demo中设置代码生成位置的原因,我们要看看它到底生成了什么。
System.setProperty ( DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/zhangyulong/Downloads" );
生成字节码的方法在Enhancer中
public void generateClass(ClassVisitor v)
底层是通过asm工具来生成的字节码,然后通过构造器反射来生成的代码逻辑。由于代码生成部分比较复杂,我们忽略这一部分,只关注一下和CallBackFilter相关的内容。
private void emitMethods(final ClassEmitter ce, List methods, List actualMethods) { ........... MethodInfo method = (MethodInfo)it1.next(); Method actualMethod = (it2 != null) ? (Method)it2.next() : null; int index = filter.accept(actualMethod); if (index >= callbackTypes.length) { throw new IllegalArgumentException("Callback filter returned an index that is too large: " + index); } originalModifiers.put(method, new Integer((actualMethod != null) ? actualMethod.getModifiers() : method.getModifiers())); indexes.put(method, new Integer(index)); List group = (List)groups.get(generators[index]); if (group == null) { groups.put(generators[index], group = new ArrayList(methods.size())); } group.add(method); ................ }
这里我们可以看到生成代理类字节码时,根据我们传入的CallbackFilter来决定使用哪个Callback。
看一下到底生成了哪些文件。
CglibTest$$EnhancerByCGLIB$$fc037646.class CglibTest$$EnhancerByCGLIB$$fc037646$$FastClassByCGLIB$$ec49b181.class CglibTest$$FastClassByCGLIB$$ef5535a6.class
在目录中我们发现生成了三个文件。首先第一个是根据CglibTest原生类来生成的代理类,第二个是原生类的FastClass,第三个是代理类的FastClass
代理类
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package cglib; 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 CglibTest$$EnhancerByCGLIB$$fc037646 extends CglibTest implements Factory { private boolean CGLIB$BOUND; public static Object CGLIB$FACTORY_DATA; private static final ThreadLocal CGLIB$THREAD_CALLBACKS; private static final Callback[] CGLIB$STATIC_CALLBACKS; private MethodInterceptor CGLIB$CALLBACK_0; private static Object CGLIB$CALLBACK_FILTER; private static final Method CGLIB$hello$0$Method; private static final MethodProxy CGLIB$hello$0$Proxy; private static final Object[] CGLIB$emptyArgs; private static final Method CGLIB$intercept$1$Method; private static final MethodProxy CGLIB$intercept$1$Proxy; private static final Method CGLIB$equals$2$Method; private static final MethodProxy CGLIB$equals$2$Proxy; private static final Method CGLIB$toString$3$Method; private static final MethodProxy CGLIB$toString$3$Proxy; private static final Method CGLIB$hashCode$4$Method; private static final MethodProxy CGLIB$hashCode$4$Proxy; private static final Method CGLIB$clone$5$Method; private static final MethodProxy CGLIB$clone$5$Proxy; static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; Class var0 = Class.forName("cglib.CglibTest$$EnhancerByCGLIB$$fc037646"); Class var1; Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods()); CGLIB$equals$2$Method = var10000[0]; CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2"); CGLIB$toString$3$Method = var10000[1]; CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3"); CGLIB$hashCode$4$Method = var10000[2]; CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4"); CGLIB$clone$5$Method = var10000[3]; CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5"); var10000 = ReflectUtils.findMethods(new String[]{"hello", "(Ljava/lang/String;)Ljava/lang/String;", "intercept", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;"}, (var1 = Class.forName("cglib.CglibTest")).getDeclaredMethods()); CGLIB$hello$0$Method = var10000[0]; CGLIB$hello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "hello", "CGLIB$hello$0"); CGLIB$intercept$1$Method = var10000[1]; CGLIB$intercept$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;", "intercept", "CGLIB$intercept$1"); } final String CGLIB$hello$0(String var1) { return super.hello(var1); } public final String hello(String var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? (String)var10000.intercept(this, CGLIB$hello$0$Method, new Object[]{var1}, CGLIB$hello$0$Proxy) : super.hello(var1); } final Object CGLIB$intercept$1(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable { return super.intercept(var1, var2, var3, var4); } public final Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? var10000.intercept(this, CGLIB$intercept$1$Method, new Object[]{var1, var2, var3, var4}, CGLIB$intercept$1$Proxy) : super.intercept(var1, var2, var3, var4); } final boolean CGLIB$equals$2(Object var1) { return super.equals(var1); } public final boolean equals(Object var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { Object var2 = var10000.intercept(this, CGLIB$equals$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy); return var2 == null ? false : (Boolean)var2; } else { return super.equals(var1); } } final String CGLIB$toString$3() { return super.toString(); } public final String toString() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy) : super.toString(); } final int CGLIB$hashCode$4() { return super.hashCode(); } public final int hashCode() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { Object var1 = var10000.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy); return var1 == null ? 0 : ((Number)var1).intValue(); } else { return super.hashCode(); } } final Object CGLIB$clone$5() throws CloneNotSupportedException { return super.clone(); } protected final Object clone() throws CloneNotSupportedException { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? var10000.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy) : super.clone(); } public static MethodProxy CGLIB$findMethodProxy(Signature var0) { String var10000 = var0.toString(); switch(var10000.hashCode()) { case -1249666147: if (var10000.equals("intercept(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;")) { return CGLIB$intercept$1$Proxy; } break; case -508378822: if (var10000.equals("clone()Ljava/lang/Object;")) { return CGLIB$clone$5$Proxy; } break; case 848333779: if (var10000.equals("hello(Ljava/lang/String;)Ljava/lang/String;")) { return CGLIB$hello$0$Proxy; } break; case 1826985398: if (var10000.equals("equals(Ljava/lang/Object;)Z")) { return CGLIB$equals$2$Proxy; } break; case 1913648695: if (var10000.equals("toString()Ljava/lang/String;")) { return CGLIB$toString$3$Proxy; } break; case 1984935277: if (var10000.equals("hashCode()I")) { return CGLIB$hashCode$4$Proxy; } } return null; } public CglibTest$$EnhancerByCGLIB$$fc037646() { CGLIB$BIND_CALLBACKS(this); } public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) { CGLIB$THREAD_CALLBACKS.set(var0); } public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) { CGLIB$STATIC_CALLBACKS = var0; } private static final void CGLIB$BIND_CALLBACKS(Object var0) { CglibTest$$EnhancerByCGLIB$$fc037646 var1 = (CglibTest$$EnhancerByCGLIB$$fc037646)var0; if (!var1.CGLIB$BOUND) { var1.CGLIB$BOUND = true; Object var10000 = CGLIB$THREAD_CALLBACKS.get(); if (var10000 == null) { var10000 = CGLIB$STATIC_CALLBACKS; if (var10000 == null) { return; } } var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0]; } } public Object newInstance(Callback[] var1) { CGLIB$SET_THREAD_CALLBACKS(var1); CglibTest$$EnhancerByCGLIB$$fc037646 var10000 = new CglibTest$$EnhancerByCGLIB$$fc037646(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Callback var1) { CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1}); CglibTest$$EnhancerByCGLIB$$fc037646 var10000 = new CglibTest$$EnhancerByCGLIB$$fc037646(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) { CGLIB$SET_THREAD_CALLBACKS(var3); CglibTest$$EnhancerByCGLIB$$fc037646 var10000 = new CglibTest$$EnhancerByCGLIB$$fc037646; switch(var1.length) { case 0: var10000.<init>(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; default: throw new IllegalArgumentException("Constructor not found"); } } public Callback getCallback(int var1) { CGLIB$BIND_CALLBACKS(this); MethodInterceptor var10000; switch(var1) { case 0: var10000 = this.CGLIB$CALLBACK_0; break; default: var10000 = null; } return var10000; } public void setCallback(int var1, Callback var2) { switch(var1) { case 0: this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2; default: } } public Callback[] getCallbacks() { CGLIB$BIND_CALLBACKS(this); return new Callback[]{this.CGLIB$CALLBACK_0}; } public void setCallbacks(Callback[] var1) { this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0]; } static { CGLIB$STATICHOOK1(); } }
代理类的FastClass
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package cglib; import cglib.CglibTest..EnhancerByCGLIB..fc037646; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import net.sf.cglib.core.Signature; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.MethodProxy; import net.sf.cglib.reflect.FastClass; public class CglibTest$$EnhancerByCGLIB$$fc037646$$FastClassByCGLIB$$ec49b181 extends FastClass { public CglibTest$$EnhancerByCGLIB$$fc037646$$FastClassByCGLIB$$ec49b181(Class var1) { super(var1); } public int getIndex(Signature var1) { String var10000 = var1.toString(); switch(var10000.hashCode()) { case -2055565910: if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) { return 3; } break; case -1457535688: if (var10000.equals("CGLIB$STATICHOOK1()V")) { return 16; } break; case -1411812934: if (var10000.equals("CGLIB$hashCode$4()I")) { return 21; } break; case -1249666147: if (var10000.equals("intercept(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;")) { return 14; } break; case -894172689: if (var10000.equals("newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) { return 11; } break; case -879968516: if (var10000.equals("CGLIB$hello$0(Ljava/lang/String;)Ljava/lang/String;")) { return 17; } break; case -623122092: if (var10000.equals("CGLIB$findMethodProxy(Lnet/sf/cglib/core/Signature;)Lnet/sf/cglib/proxy/MethodProxy;")) { return 0; } break; case -508378822: if (var10000.equals("clone()Ljava/lang/Object;")) { return 9; } break; case -419626537: if (var10000.equals("setCallbacks([Lnet/sf/cglib/proxy/Callback;)V")) { return 1; } break; case 374345669: if (var10000.equals("CGLIB$equals$2(Ljava/lang/Object;)Z")) { return 19; } break; case 560567118: if (var10000.equals("setCallback(ILnet/sf/cglib/proxy/Callback;)V")) { return 15; } break; case 811063227: if (var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) { return 12; } break; case 848333779: if (var10000.equals("hello(Ljava/lang/String;)Ljava/lang/String;")) { return 13; } break; case 973717575: if (var10000.equals("getCallbacks()[Lnet/sf/cglib/proxy/Callback;")) { return 5; } break; case 1115619315: if (var10000.equals("CGLIB$intercept$1(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;")) { return 18; } break; case 1221173700: if (var10000.equals("newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) { return 10; } break; case 1230699260: if (var10000.equals("getCallback(I)Lnet/sf/cglib/proxy/Callback;")) { return 4; } break; case 1341835395: if (var10000.equals("main([Ljava/lang/String;)V")) { return 23; } break; case 1517819849: if (var10000.equals("CGLIB$toString$3()Ljava/lang/String;")) { return 20; } break; case 1584330438: if (var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) { return 2; } break; case 1826985398: if (var10000.equals("equals(Ljava/lang/Object;)Z")) { return 6; } break; case 1913648695: if (var10000.equals("toString()Ljava/lang/String;")) { return 7; } break; case 1984935277: if (var10000.equals("hashCode()I")) { return 8; } break; case 2011844968: if (var10000.equals("CGLIB$clone$5()Ljava/lang/Object;")) { return 22; } } return -1; } public int getIndex(String var1, Class[] var2) { switch(var1.hashCode()) { case -1776922004: if (var1.equals("toString")) { switch(var2.length) { case 0: return 7; } } break; case -1295482945: if (var1.equals("equals")) { switch(var2.length) { case 1: if (var2[0].getName().equals("java.lang.Object")) { return 6; } } } break; case -1053468136: if (var1.equals("getCallbacks")) { switch(var2.length) { case 0: return 5; } } break; case -981624788: if (var1.equals("CGLIB$intercept$1")) { switch(var2.length) { case 4: if (var2[0].getName().equals("java.lang.Object") && var2[1].getName().equals("java.lang.reflect.Method") && var2[2].getName().equals("[Ljava.lang.Object;") && var2[3].getName().equals("net.sf.cglib.proxy.MethodProxy")) { return 18; } } } break; case -124978608: if (var1.equals("CGLIB$equals$2")) { switch(var2.length) { case 1: if (var2[0].getName().equals("java.lang.Object")) { return 19; } } } break; case -60403779: if (var1.equals("CGLIB$SET_STATIC_CALLBACKS")) { switch(var2.length) { case 1: if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) { return 2; } } } break; case -29025554: if (var1.equals("CGLIB$hashCode$4")) { switch(var2.length) { case 0: return 21; } } break; case 3343801: if (var1.equals("main")) { switch(var2.length) { case 1: if (var2[0].getName().equals("[Ljava.lang.String;")) { return 23; } } } break; case 85179481: if (var1.equals("CGLIB$SET_THREAD_CALLBACKS")) { switch(var2.length) { case 1: if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) { return 3; } } } break; case 94756189: if (var1.equals("clone")) { switch(var2.length) { case 0: return 9; } } break; case 99162322: if (var1.equals("hello")) { switch(var2.length) { case 1: if (var2[0].getName().equals("java.lang.String")) { return 13; } } } break; case 147696667: if (var1.equals("hashCode")) { switch(var2.length) { case 0: return 8; } } break; case 161998109: if (var1.equals("CGLIB$STATICHOOK1")) { switch(var2.length) { case 0: return 16; } } break; case 495524492: if (var1.equals("setCallbacks")) { switch(var2.length) { case 1: if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) { return 1; } } } break; case 502538434: if (var1.equals("intercept")) { switch(var2.length) { case 4: if (var2[0].getName().equals("java.lang.Object") && var2[1].getName().equals("java.lang.reflect.Method") && var2[2].getName().equals("[Ljava.lang.Object;") && var2[3].getName().equals("net.sf.cglib.proxy.MethodProxy")) { return 14; } } } break; case 1154623345: if (var1.equals("CGLIB$findMethodProxy")) { switch(var2.length) { case 1: if (var2[0].getName().equals("net.sf.cglib.core.Signature")) { return 0; } } } break; case 1543336190: if (var1.equals("CGLIB$toString$3")) { switch(var2.length) { case 0: return 20; } } break; case 1811874389: if (var1.equals("newInstance")) { switch(var2.length) { case 1: String var10001 = var2[0].getName(); switch(var10001.hashCode()) { case -845341380: if (var10001.equals("net.sf.cglib.proxy.Callback")) { return 11; } break; case 1730110032: if (var10001.equals("[Lnet.sf.cglib.proxy.Callback;")) { return 10; } } case 2: default: break; case 3: if (var2[0].getName().equals("[Ljava.lang.Class;") && var2[1].getName().equals("[Ljava.lang.Object;") && var2[2].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) { return 12; } } } break; case 1817099975: if (var1.equals("setCallback")) { switch(var2.length) { case 2: if (var2[0].getName().equals("int") && var2[1].getName().equals("net.sf.cglib.proxy.Callback")) { return 15; } } } break; case 1891304123: if (var1.equals("CGLIB$hello$0")) { switch(var2.length) { case 1: if (var2[0].getName().equals("java.lang.String")) { return 17; } } } break; case 1905679803: if (var1.equals("getCallback")) { switch(var2.length) { case 1: if (var2[0].getName().equals("int")) { return 4; } } } break; case 1951977611: if (var1.equals("CGLIB$clone$5")) { switch(var2.length) { case 0: return 22; } } } return -1; } public int getIndex(Class[] var1) { switch(var1.length) { case 0: return 0; default: return -1; } } public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException { fc037646 var10000 = (fc037646)var2; int var10001 = var1; try { switch(var10001) { case 0: return fc037646.CGLIB$findMethodProxy((Signature)var3[0]); case 1: var10000.setCallbacks((Callback[])var3[0]); return null; case 2: fc037646.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]); return null; case 3: fc037646.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]); return null; case 4: return var10000.getCallback(((Number)var3[0]).intValue()); case 5: return var10000.getCallbacks(); case 6: return new Boolean(var10000.equals(var3[0])); case 7: return var10000.toString(); case 8: return new Integer(var10000.hashCode()); case 9: return var10000.clone(); case 10: return var10000.newInstance((Callback[])var3[0]); case 11: return var10000.newInstance((Callback)var3[0]); case 12: return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]); case 13: return var10000.hello((String)var3[0]); case 14: return var10000.intercept(var3[0], (Method)var3[1], (Object[])var3[2], (MethodProxy)var3[3]); case 15: var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]); return null; case 16: fc037646.CGLIB$STATICHOOK1(); return null; case 17: return var10000.CGLIB$hello$0((String)var3[0]); case 18: return var10000.CGLIB$intercept$1(var3[0], (Method)var3[1], (Object[])var3[2], (MethodProxy)var3[3]); case 19: return new Boolean(var10000.CGLIB$equals$2(var3[0])); case 20: return var10000.CGLIB$toString$3(); case 21: return new Integer(var10000.CGLIB$hashCode$4()); case 22: return var10000.CGLIB$clone$5(); case 23: CglibTest.main((String[])var3[0]); return null; } } catch (Throwable var4) { throw new InvocationTargetException(var4); } throw new IllegalArgumentException("Cannot find matching method/constructor"); } public Object newInstance(int var1, Object[] var2) throws InvocationTargetException { fc037646 var10000 = new fc037646; fc037646 var10001 = var10000; int var10002 = var1; try { switch(var10002) { case 0: var10001.<init>(); return var10000; } } catch (Throwable var3) { throw new InvocationTargetException(var3); } throw new IllegalArgumentException("Cannot find matching method/constructor"); } public int getMaxIndex() { return 23; } }
原生类的FastClass
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package cglib; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import net.sf.cglib.core.Signature; import net.sf.cglib.proxy.MethodProxy; import net.sf.cglib.reflect.FastClass; public class CglibTest$$FastClassByCGLIB$$ef5535a6 extends FastClass { public CglibTest$$FastClassByCGLIB$$ef5535a6(Class var1) { super(var1); } public int getIndex(Signature var1) { String var10000 = var1.toString(); switch(var10000.hashCode()) { case -1249666147: if (var10000.equals("intercept(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;")) { return 2; } break; case 848333779: if (var10000.equals("hello(Ljava/lang/String;)Ljava/lang/String;")) { return 1; } break; case 1341835395: if (var10000.equals("main([Ljava/lang/String;)V")) { return 0; } break; case 1826985398: if (var10000.equals("equals(Ljava/lang/Object;)Z")) { return 3; } break; case 1913648695: if (var10000.equals("toString()Ljava/lang/String;")) { return 4; } break; case 1984935277: if (var10000.equals("hashCode()I")) { return 5; } } return -1; } public int getIndex(String var1, Class[] var2) { switch(var1.hashCode()) { case -1776922004: if (var1.equals("toString")) { switch(var2.length) { case 0: return 4; } } break; case -1295482945: if (var1.equals("equals")) { switch(var2.length) { case 1: if (var2[0].getName().equals("java.lang.Object")) { return 3; } } } break; case 3343801: if (var1.equals("main")) { switch(var2.length) { case 1: if (var2[0].getName().equals("[Ljava.lang.String;")) { return 0; } } } break; case 99162322: if (var1.equals("hello")) { switch(var2.length) { case 1: if (var2[0].getName().equals("java.lang.String")) { return 1; } } } break; case 147696667: if (var1.equals("hashCode")) { switch(var2.length) { case 0: return 5; } } break; case 502538434: if (var1.equals("intercept")) { switch(var2.length) { case 4: if (var2[0].getName().equals("java.lang.Object") && var2[1].getName().equals("java.lang.reflect.Method") && var2[2].getName().equals("[Ljava.lang.Object;") && var2[3].getName().equals("net.sf.cglib.proxy.MethodProxy")) { return 2; } } } } return -1; } public int getIndex(Class[] var1) { switch(var1.length) { case 0: return 0; default: return -1; } } public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException { CglibTest var10000 = (CglibTest)var2; int var10001 = var1; try { switch(var10001) { case 0: CglibTest.main((String[])var3[0]); return null; case 1: return var10000.hello((String)var3[0]); case 2: return var10000.intercept(var3[0], (Method)var3[1], (Object[])var3[2], (MethodProxy)var3[3]); case 3: return new Boolean(var10000.equals(var3[0])); case 4: return var10000.toString(); case 5: return new Integer(var10000.hashCode()); } } catch (Throwable var4) { throw new InvocationTargetException(var4); } throw new IllegalArgumentException("Cannot find matching method/constructor"); } public Object newInstance(int var1, Object[] var2) throws InvocationTargetException { CglibTest var10000 = new CglibTest; CglibTest var10001 = var10000; int var10002 = var1; try { switch(var10002) { case 0: var10001.<init>(); return var10000; } } catch (Throwable var3) { throw new InvocationTargetException(var3); } throw new IllegalArgumentException("Cannot find matching method/constructor"); } public int getMaxIndex() { return 5; } }
我们看下代理类的hello方法
public final String hello(String var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? (String)var10000.intercept(this, CGLIB$hello$0$Method, new Object[]{var1}, CGLIB$hello$0$Proxy) : super.hello(var1); }
最终调用了 var10000.intercept(this, CGLIB$hello$0$Method, new Object[]{var1}, CGLIB$hello$0$Proxy)方法,也就是我们的
@Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println ("我被代理了"); return proxy.invokeSuper ( obj,args ); }
proxy.invokeSuper ( obj,args ) 是怎么实现的呢,接下来我们重点看看 CGLIB$hello$0$Proxy的生成逻辑。
CGLIB$hello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "hello", "CGLIB$hello$0"); public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) { MethodProxy proxy = new MethodProxy(); proxy.sig1 = new Signature(name1, desc); proxy.sig2 = new Signature(name2, desc); proxy.createInfo = new CreateInfo(c1, c2); return proxy; }
这里根据代理类以及原生类的hello方法生成了方法签名 Signature。
5个参数分别是 Class c1 目标类Class,Class c2 代理类Class,String desc 代理方法的描述,String name1 被代理方法名,String name2 代理方法名
接下来
public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { init(); FastClassInfo fci = fastClassInfo; return fci.f2.invoke(fci.i2, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } }
private void init() { /* * Using a volatile invariant allows us to initialize the FastClass and * method index pairs atomically. * * Double-checked locking is safe with volatile in Java 5. Before 1.5 this * code could allow fastClassInfo to be instantiated more than once, which * appears to be benign. */ if (fastClassInfo == null) { synchronized (initLock) { if (fastClassInfo == null) { CreateInfo ci = createInfo; FastClassInfo fci = new FastClassInfo(); fci.f1 = helper(ci, ci.c1); fci.f2 = helper(ci, ci.c2); fci.i1 = fci.f1.getIndex(sig1); fci.i2 = fci.f2.getIndex(sig2); fastClassInfo = fci; } } } } private static class FastClassInfo { FastClass f1; FastClass f2; int i1; int i2; } private static class CreateInfo { Class c1; Class c2; NamingPolicy namingPolicy; GeneratorStrategy strategy; boolean attemptLoad; public CreateInfo(Class c1, Class c2) { this.c1 = c1; this.c2 = c2; AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent(); if (fromEnhancer != null) { namingPolicy = fromEnhancer.getNamingPolicy(); strategy = fromEnhancer.getStrategy(); attemptLoad = fromEnhancer.getAttemptLoad(); } } } private static FastClass helper(CreateInfo ci, Class type) { FastClass.Generator g = new FastClass.Generator(); g.setType(type); g.setClassLoader(ci.c2.getClassLoader()); g.setNamingPolicy(ci.namingPolicy); g.setStrategy(ci.strategy); g.setAttemptLoad(ci.attemptLoad); return g.create(); }
其实这里最主要的就是生成代理类和普通类的FastClass,以及hello方法的index,然后去调用,我们看一下简单的例子来看看FastClass底层倒底是什么
public class FastClass1 { public void hello(String name) { System.out.println("hello, " + name); } public void hi(String msg) { System.out.println("hi, " + msg); } } public class FastClass2 { public Object invoke(Object obj, int methodIndex, Object[] parameters) { FastClass1 target = (FastClass1)obj; Object result = null; switch (methodIndex) { case 1: target.hello((String)parameters[0]); break; case 2: target.hi((String)parameters[0]); break; } return result; } public int getIndex(String methodDescriptor) { switch (methodDescriptor.hashCode()) { case -2084786067: return 1; case -70025314: return 2; } return -1; } } public class FastClassTest { public static void main(String[] args) { FastClass1 fastClass1 = new FastClass1(); FastClass2 fastClass2 = new FastClass2(); int helloIndex = fastClass2.getIndex("hello(Ljava/lang/String;)V");//方法名(参数类型;...)返回类型 fastClass2.invoke(fastClass1, helloIndex, new Object[]{"张三"}); int hiIndex = fastClass2.getIndex("hi(Ljava/lang/String;)V"); fastClass2.invoke(fastClass1, hiIndex, new Object[]{"cglib动态代理"}); } }
上例中,FastClass2是FastClass1的Fastclass,在FastClass2中有两个方法getIndex和invoke。在getIndex方法中对FastClass1的每个方法建立索引,并根据入参(方法名+方法的描述符)来返回相应的索引。invoke根据指定的索引,以parameters为入参调用对象obj的方法。这样就避免了反射调用,提高了效率。我们生成的CglibTest$$EnhancerByCGLIB$$fc037646$$FastClassByCGLIB$$ec49b181.class以及CglibTest$$FastClassByCGLIB$$ef5535a6.class 原理也是类似。
MethodProxy中invokeSuper 和MethodProxy中invoke的区别是什么 我们来看看
public Object invoke(Object obj, Object[] args) throws Throwable { try { init(); FastClassInfo fci = fastClassInfo; return fci.f1.invoke(fci.i1, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } catch (IllegalArgumentException e) { if (fastClassInfo.i1 < 0) throw new IllegalArgumentException("Protected method: " + sig1); throw e; } } public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { init(); FastClassInfo fci = fastClassInfo; return fci.f2.invoke(fci.i2, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } }
fci.f1.invoke(fci.i1, obj, args);执行原生类Fastclass的hello方法
fci.f2.invoke(fci.i2, obj, args);执行代理类FastClass的hello方法
经常有小伙伴不小心用错的逻辑,导致死循环。
@Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println ("我被代理了"); return proxy.invoke ( obj,args ); } ......... 我被代理了 我被代理了 我被代理了 Exception in thread "main" java.lang.StackOverflowError at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:77) at sun.nio.cs.UTF_8.access$200(UTF_8.java:57) at sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(UTF_8.java:636) at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:691) at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:579) at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:271) at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125) at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207) at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129) at java.io.PrintStream.write(PrintStream.java:526) at java.io.PrintStream.print(PrintStream.java:669) at java.io.PrintStream.println(PrintStream.java:806) at cglib.CglibTest.intercept(CglibTest.java:13) at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>) at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>) at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at cglib.CglibTest.intercept(CglibTest.java:14) at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>) at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>) at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at cglib.CglibTest.intercept(CglibTest.java:14) at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>) at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>) at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at cglib.CglibTest.intercept(CglibTest.java:14) at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>) at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>) at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at cglib.CglibTest.intercept(CglibTest.java:14) at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>) at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>) at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at cglib.CglibTest.intercept(CglibTest.java:14) at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>) at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>) at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at cglib.CglibTest.intercept(CglibTest.java:14) at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>) at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>) .........
为什么会这样,因为invokeSuper执行的是代理类的FastClass的方法,invoke是执行的原生类的FastClass的方法,
CGLIB$hello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "hello", "CGLIB$hello$0");
最终执行的方法不一样,分别是hello以及CGLIB$hello$0
final String CGLIB$hello$1(String var1) { return super.hello(var1); } public final String hello(String var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? (String)var10000.intercept(this, CGLIB$hello$1$Method, new Object[]{var1}, CGLIB$hello$1$Proxy) : super.hello(var1); }
执行CGLIB$hello$1方法最终调用原生方法,执行hello方法会一直执行MethodInterceptor的intercept方法导致死循环,最后还有一点拦截器在cglib中可以实现很多类型,这个也是在字节码生成代码中来实现的,Spring等框架常用的就MethodInterceptor
class CallbackInfo { private static final CallbackInfo[] CALLBACKS = { new CallbackInfo(NoOp.class, NoOpGenerator.INSTANCE), new CallbackInfo(MethodInterceptor.class, MethodInterceptorGenerator.INSTANCE), new CallbackInfo(InvocationHandler.class, InvocationHandlerGenerator.INSTANCE), new CallbackInfo(LazyLoader.class, LazyLoaderGenerator.INSTANCE), new CallbackInfo(Dispatcher.class, DispatcherGenerator.INSTANCE), new CallbackInfo(FixedValue.class, FixedValueGenerator.INSTANCE), new CallbackInfo(ProxyRefDispatcher.class, DispatcherGenerator.PROXY_REF_INSTANCE), }; }
我们常用的callBack就是MethodInterceptor,但是其他的可能不太常用,他们的区别是什么呢,来看下面的代码
package cglib.callback; import net.sf.cglib.core.DebuggingClassWriter; import net.sf.cglib.proxy.*; import java.lang.reflect.Method; public class CglibTestCallBack { public String hello0(String name){ return "你好0" + name; } public String hello1(String name){ return "你好1" + name; } public String hello2(String name){ return "你好2" + name; } public String hello3(String name){ return "你好3" + name; } public String hello4(String name){ return "你好4" + name; } public String hello5(String name){ return "你好5" + name; } public String hello6(String name){ return "你好6" + name; } public static void main(String[] args) { System.setProperty ( DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/zhangyulong/Downloads" ); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass ( CglibTestCallBack.class); enhancer.setCallbacks( new Callback[]{ new DispatcherCallBack(), new FixedValueCallBack(), new InvocationHandlerCallback(), new LazyLoaderCallBack(), new MethodInterceptorCallBack(), new NoOpCallBack(), new ProxyRefDispatcherCallBack() } ); enhancer.setCallbackFilter ( new CallbackFilter () { @Override public int accept(Method method) { String name = method.getName (); if(!name.startsWith ( "hello" )) return 0; String num = name.substring ( "hello".length () ); return Integer.parseInt ( num ); } } ); CglibTestCallBack cglibTest = (CglibTestCallBack) enhancer.create (); String result = cglibTest.hello1 ( "张玉龙" ); System.out.println (result); } }
public class DispatcherCallBack implements Dispatcher { @Override public Object loadObject() throws Exception { return null; } } public class FixedValueCallBack implements FixedValue { @Override public Object loadObject() throws Exception { return null; } } public class InvocationHandlerCallback implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return null; } } public class LazyLoaderCallBack implements LazyLoader { @Override public Object loadObject() throws Exception { return null; } } public class NoOpCallBack implements NoOp { } public class ProxyRefDispatcherCallBack implements ProxyRefDispatcher { @Override public Object loadObject(Object proxy) throws Exception { return null; } }
我们设置了六个callBack,对应了六个方法 hello0-6, 我们来看看他们生成的代理类的方法是什么样的,下面是代理类的部分代码
public final String hello0(String var1) { Dispatcher var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return ((CglibTestCallBack)var10000.loadObject()).hello0(var1); } public final String hello1(String var1) { FixedValue var10000 = this.CGLIB$CALLBACK_1; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_1; } return (String)var10000.loadObject(); } public final String hello2(String var1) { try { InvocationHandler var10000 = this.CGLIB$CALLBACK_2; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_2; } return (String)var10000.invoke(this, CGLIB$hello2$1, new Object[]{var1}); } catch (Error | RuntimeException var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String hello3(String var1) { return ((CglibTestCallBack)this.CGLIB$LOAD_PRIVATE_3()).hello3(var1); } private final synchronized Object CGLIB$LOAD_PRIVATE_3() { Object var10000 = this.CGLIB$LAZY_LOADER_3; if (var10000 == null) { LazyLoader var10001 = this.CGLIB$CALLBACK_3; if (var10001 == null) { CGLIB$BIND_CALLBACKS(this); var10001 = this.CGLIB$CALLBACK_3; } var10000 = this.CGLIB$LAZY_LOADER_3 = var10001.loadObject(); } return var10000; } public final String hello4(String var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_4; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_4; } return var10000 != null ? (String)var10000.intercept(this, CGLIB$hello4$3$Method, new Object[]{var1}, CGLIB$hello4$3$Proxy) : super.hello4(var1); } public final String hello6(String var1) { ProxyRefDispatcher var10000 = this.CGLIB$CALLBACK_6; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_6; } return ((CglibTestCallBack)var10000.loadObject(this)).hello6(var1); }
无需多解释,生成的代码非常清晰了,由于hello5是实现了NoOp,代理类忽略这个方法,直接调用原生类的hello5。值得注意的是CGLIB$BIND_CALLBACKS(this);这个方法是这些代理方法中统一的设置callback的方法,我们看看它到底干了些什么。
private static final void CGLIB$BIND_CALLBACKS(Object var0) { CglibTestCallBack$$EnhancerByCGLIB$$58712cb6 var1 = (CglibTestCallBack$$EnhancerByCGLIB$$58712cb6)var0; if (!var1.CGLIB$BOUND) { var1.CGLIB$BOUND = true; Object var10000 = CGLIB$THREAD_CALLBACKS.get(); if (var10000 == null) { var10000 = CGLIB$STATIC_CALLBACKS; if (var10000 == null) { return; } } Callback[] var10001 = (Callback[])var10000; var1.CGLIB$CALLBACK_6 = (ProxyRefDispatcher)((Callback[])var10000)[6]; var1.CGLIB$CALLBACK_5 = (NoOp)var10001[5]; var1.CGLIB$CALLBACK_4 = (MethodInterceptor)var10001[4]; var1.CGLIB$CALLBACK_3 = (LazyLoader)var10001[3]; var1.CGLIB$CALLBACK_2 = (InvocationHandler)var10001[2]; var1.CGLIB$CALLBACK_1 = (FixedValue)var10001[1]; var1.CGLIB$CALLBACK_0 = (Dispatcher)var10001[0]; } }
代码非常简单,就是从CGLIB$THREAD_CALLBACKS 或者CGLIB$STATIC_CALLBACKS中获取callBack数组,那么这个数组我们什么时候设置的呢?看下面代码 net.sf.cglib.proxy.Enhancer#firstInstance
protected Object firstInstance(Class type) throws Exception { if (classOnly) { return type; } else { return createUsingReflection(type); } } private Object createUsingReflection(Class type) { setThreadCallbacks(type, callbacks); try{ if (argumentTypes != null) { return ReflectUtils.newInstance(type, argumentTypes, arguments); } else { return ReflectUtils.newInstance(type); } }finally{ // clear thread callbacks to allow them to be gc'd setThreadCallbacks(type, null); } } private static final String SET_THREAD_CALLBACKS_NAME = "CGLIB$SET_THREAD_CALLBACKS"; private static void setThreadCallbacks(Class type, Callback[] callbacks) { setCallbacksHelper(type, callbacks, SET_THREAD_CALLBACKS_NAME); }
特别明显在初始化时,将我们设置的callBack数组设置到代理类中,并且在代理类生成实例之后,再清空,方便gc回收,到此cglib的源码解析就已经完成了。这里有一个细节就是上面的代码 只有hello4方法才会生成FastClass,所以我们生成的代理类只有1个,没有生成原生类和代理的FsstClass,这是因为fastclass的生成只有首次调用方法的时候,才会去触发。
public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { init(); FastClassInfo fci = fastClassInfo; return fci.f2.invoke(fci.i2, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } }
所以当我们调用hello4方法时,首次调用就会生成代理类了。这也就是为什么cglib代理首次调用的时候速度会慢一些,因为要先生成字节码。
四:手把手写基于接口的java代理
上面我们分析了jdk动态代理源码、cglib代理源码、那我们是不是可以自己用自己的方式去写一个属于自己的jdk代理呢,答案是可以的
首先我们写一个基类,当然我并没有在基类里面写什么东西,只是模拟java中的proxy类而已,当然我们也可以丰富的去拓展一下这个类的方法,来实现更多的功能,读者可以通过读完这篇文章之后自己去考虑一下如何来拓展。
1 package meituan.zylproxy.handlder; 2 public class ZylProxy { 3 public ZylProxy(){ 4 } 5 }
代理的核心接口,我们去做代理的时候一定是通过反射去调用的,不管jdk也好还是cglib也好,永远也无法脱离反射,我们照猫画虎,自己写一个代理接口核心类,这并不是什么难题,看起来和jdk的核心类接口也没有什么区别。
1 package meituan.zylproxy.handlder; 2 3 import java.lang.reflect.Method; 4 5 public interface ZYLInvocationHandler { 6 7 public Object invoke(Object proxy, Method method, Object[] args) 8 throws Exception; 9 }
说明一下 第一个参数proxy是代表代理类,而不是用户自己写的原生类实现。参数Method是接口的方法,args是运行时参数列表,在运行时传递过来的实际上就是实现类的参数,好了,下面让我们去深入核心。
我们自定义两个接口和接口的实现Idto,Idto2,和Dtoimpl如下:
1 package meituan.zylproxy.test.i; 2 3 public interface Idto { 4 5 public void add(); 6 7 public String get(); 8 9 }
package meituan.zylproxy.test.i; public interface Idto2 { public void adda(); public String geta(); }
package meituan.zylproxy.test.i.impl; import meituan.zylproxy.test.i.Idto; import meituan.zylproxy.test.i.Idto2; public class DtoImpl implements Idto,Idto2{ @Override public void add() { System.out.println("add"); } @Override public String get() { System.out.println("get"); return "return get"; } @Override public void adda() { System.out.println("adda"); } @Override public String geta() { System.out.println("geta"); return "return geta"; } }
这是几个再简单不过的接口和实现类了,也没有什么可说的。接下来我们想对接口进行代理,无非是我们动态将接口进行实现,从而达到对使用者进行自定义handle接口暴露而已,下面看一下我们需要生成一个什么样的代理类。
import java.lang.reflect.Method; import meituan.zylproxy.handlder.ZylProxy; import meituan.zylproxy.handlder.ZYLInvocationHandler; import meituan.zylproxy.test.i.Idto; import meituan.zylproxy.test.i.Idto2; public class IdtoPorxy extends ZylProxy implements Idto, Idto2 { public ZYLInvocationHandler zYLInvocationHandler; public static Method add1; public static Method get2; public static Method adda3; public static Method geta4; static { try { add1 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "add", new Class[0] ); get2 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "get", new Class[0] ); adda3 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "adda", new Class[0] ); geta4 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "geta", new Class[0] ); } catch (Exception e) { } } public IdtoPorxy(ZYLInvocationHandler zYLInvocationHandler) { this.zYLInvocationHandler = zYLInvocationHandler; } public void add() { Object[] o = {}; try { this.zYLInvocationHandler.invoke ( this, add1, o ); return; } catch (Throwable e) { e.printStackTrace (); } } public java.lang.String get() { Object[] o = {}; try { return (java.lang.String) this.zYLInvocationHandler.invoke ( this, get2, o ); } catch (Exception e) { e.printStackTrace (); } return null; } public void adda() { Object[] o = {}; try { this.zYLInvocationHandler.invoke ( this, adda3, o ); return; } catch (Throwable e) { e.printStackTrace (); } } public java.lang.String geta() { Object[] o = {}; try { return (java.lang.String) this.zYLInvocationHandler.invoke ( this, geta4, o ); } catch (Exception e) { e.printStackTrace (); } return null; } }
这个类不是由用户写的,而是我们动态生成的,对于jdk来说是生成了字节码,对cglib来说是通过字节码增强,其实实现的方式有多种,后面为了更方便大家理解我用字符串的形式来动态生成这么一个"家伙",先看看这个类干了些什么吧,也很简单。
public class IdtoPorxy extends ZylProxy implements Idto, Idto2
首先是继承了刚才我们所说的ZylProxy,留着今后拓展,可以参照java的Proxy,然后并且动态的实现了这两个接口。很简单
public ZYLInvocationHandler zYLInvocationHandler;
public IdtoPorxy(ZYLInvocationHandler zYLInvocationHandler) {
this.zYLInvocationHandler = zYLInvocationHandler;
}
这个是通过构造函数传进来一个handler对象,对实现类的操作都靠它了。
public static Method add1; public static Method get2; public static Method adda3; public static Method geta4; static { try { add1 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "add", new Class[0] ); get2 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "get", new Class[0] ); adda3 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "adda", new Class[0] ); geta4 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "geta", new Class[0] ); } catch (Exception e) { } }
枚举出来所有的接口的方法,通过class.forname来获取到Method元数据。备用
public void add() { Object[] o = {}; try { this.zYLInvocationHandler.invoke ( this, add1, o ); return; } catch (Throwable e) { e.printStackTrace (); } } public java.lang.String get() { Object[] o = {}; try { return (java.lang.String) this.zYLInvocationHandler.invoke ( this, get2, o ); } catch (Exception e) { e.printStackTrace (); } return null; } public void adda() { Object[] o = {}; try { this.zYLInvocationHandler.invoke ( this, adda3, o ); return; } catch (Throwable e) { e.printStackTrace (); } } public java.lang.String geta() { Object[] o = {}; try { return (java.lang.String) this.zYLInvocationHandler.invoke ( this, geta4, o ); } catch (Exception e) { e.printStackTrace (); } return null; }
上面是要枚举出来所有的方法的实现,很简单都一个模样,把实现交给handler去做就可以了。至于怎么实现靠handler,我们动态生成的这个类只负责委托,不做任何事情。看到这里大家一定急不可待的想知道这个类怎么生成的了,我把我写的源码给大家贴出来看一下。
package meituan.zylproxy.util; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import meituan.zylproxy.test.i.Idto; import meituan.zylproxy.test.i.Idto2; public class ClassUtil { public static String mackProxyClass(Class<?> c) throws Exception{ if(!c.isInterface()){ throw new Exception("代理的类必须是接口"); } StringBuffer importsp = new StringBuffer(); importsp.append("import java.lang.reflect.Method;\n"); importsp.append("import meituan.zylproxy.handlder.ZylProxy;\n"); importsp.append("import meituan.zylproxy.handlder.ZYLInvocationHandler;\n"); importsp.append("import " +c.getName() + ";\n"); StringBuilder publicStaticMethods = new StringBuilder(); //public static Method add; StringBuilder publicMethods = new StringBuilder(); publicMethods.append("public ZYLInvocationHandler zYLInvocationHandler;\n"); StringBuilder constructorsp = new StringBuilder(); String interFaceName = c.getName().substring(c.getName().lastIndexOf(".")+1); constructorsp.append("public ").append("" + interFaceName + "Porxy"). append("(ZYLInvocationHandler zYLInvocationHandler) { " + "this.zYLInvocationHandler = zYLInvocationHandler;" + "}"); publicStaticMethods.append(" static { try { "); StringBuilder classsp = new StringBuilder(); classsp.append("public class").append(" " + interFaceName + "Porxy").append(" extends ZylProxy implements ").append(interFaceName).append("{"); StringBuilder allMethods = new StringBuilder(); Method[] Methods = c.getMethods(); int curr=0; for (Method m_:Methods) { curr++; publicMethods.append("public static Method ").append(m_.getName() + String.valueOf(curr)).append(";\n"); publicStaticMethods.append("").append(m_.getName() + String.valueOf(curr)).append("="); publicStaticMethods.append("Class.forName(\"" + c.getName() + "\")" + ".getMethod(\""+ m_.getName() +"\", "); StringBuilder sp =new StringBuilder(); StringBuilder spArgs = new StringBuilder(); spArgs.append("Object[] o ={"); //public sp.append(Modifier.toString(m_.getModifiers()).replace("abstract", "")).append(" "); //void | java.lang.String sp.append(m_.getReturnType().getName()).append(" "); //add()|get() sp.append(m_.getName().concat("(")); StringBuilder methodCLass = new StringBuilder(); if(m_.getParameterTypes().length>0){ Class<?>[] claszz = m_.getParameterTypes(); int methodOffset = 0; methodCLass.append("new Class[] { "); for (Class<?> c_ : claszz) { String paramStr = "obj" + String.valueOf(++methodOffset); spArgs.append(paramStr.concat(",")); sp.append(c_.getName().toString().concat(" ").concat(paramStr)).append(","); methodCLass.append("Class.forName(\"" + c_.getName()).append("\"),"); } sp = new StringBuilder(sp.substring(0, sp.length()-1)); spArgs = new StringBuilder(spArgs.substring(0, spArgs.length()-1)); methodCLass = new StringBuilder(methodCLass.substring(0, methodCLass.length()-1)); } if(methodCLass.length()>0){ methodCLass.append("}"); } else{ methodCLass.append("new Class[0]"); } sp.append("){\n"); spArgs.append("}"); sp.append(spArgs+";\n"); if(sp.toString().contains("void")){ sp.append("try {\n this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n return;\n"); sp.append("} catch (Throwable e) {e.printStackTrace();}}"); } else{ sp.append("try {return " + "(" + m_.getReturnType().getName() + ")" + "this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n"); sp.append("} catch (Exception e) {e.printStackTrace();} return null;"); } publicStaticMethods.append(methodCLass).append(");\n"); allMethods.append(sp); } publicStaticMethods.append("} catch(Exception e){}}"); classsp.append(publicMethods) .append(publicStaticMethods) .append(constructorsp).append(allMethods).append("}"); classsp.append("}"); importsp.append(classsp); return importsp.toString(); } public static String mackMultiProxyClass(Class<?>[] cs) throws Exception{ StringBuffer importsp = new StringBuffer(); importsp.append("import java.lang.reflect.Method;\n"); importsp.append("import meituan.zylproxy.handlder.ZylProxy;\n"); importsp.append("import meituan.zylproxy.handlder.ZYLInvocationHandler;\n"); StringBuilder publicStaticMethods = new StringBuilder(); publicStaticMethods.append(" static { try { "); //public static Method add; StringBuilder publicMethods = new StringBuilder(); publicMethods.append("public ZYLInvocationHandler zYLInvocationHandler;\n"); int curr=0; StringBuilder constructorsp = new StringBuilder(); String interFaceName = cs[0].getName().substring(cs[0].getName().lastIndexOf(".")+1); constructorsp.append("public ").append("" + interFaceName + "Porxy"). append("(ZYLInvocationHandler zYLInvocationHandler) { " + "this.zYLInvocationHandler = zYLInvocationHandler;" + "}"); StringBuilder allMethods = new StringBuilder(); StringBuilder classsp = new StringBuilder(); classsp.append("public class").append(" " + interFaceName + "Porxy").append(" extends ZylProxy implements "); for (Class<?> c:cs) { if(!c.isInterface()){ throw new Exception("代理的类必须是接口"); } classsp.append(c.getName().substring(c.getName().lastIndexOf(".")+1)).append(","); importsp.append("import " +c.getName() + ";\n"); Method[] Methods = c.getMethods(); for (Method m_:Methods) { curr++; publicMethods.append("public static Method ").append(m_.getName() + String.valueOf(curr)).append(";\n"); publicStaticMethods.append("").append(m_.getName() + String.valueOf(curr)).append("="); publicStaticMethods.append("Class.forName(\"" + c.getName() + "\")" + ".getMethod(\""+ m_.getName() +"\", "); StringBuilder sp =new StringBuilder(); StringBuilder spArgs = new StringBuilder(); spArgs.append("Object[] o ={"); //public sp.append(Modifier.toString(m_.getModifiers()).replace("abstract", "")).append(" "); //void | java.lang.String sp.append(m_.getReturnType().getName()).append(" "); //add()|get() sp.append(m_.getName().concat("(")); StringBuilder methodCLass = new StringBuilder(); if(m_.getParameterTypes().length>0){ Class<?>[] claszz = m_.getParameterTypes(); int methodOffset = 0; methodCLass.append("new Class[] { "); for (Class<?> c_ : claszz) { String paramStr = "obj" + String.valueOf(++methodOffset); spArgs.append(paramStr.concat(",")); sp.append(c_.getName().toString().concat(" ").concat(paramStr)).append(","); methodCLass.append("Class.forName(\"" + c_.getName()).append("\"),"); } sp = new StringBuilder(sp.substring(0, sp.length()-1)); spArgs = new StringBuilder(spArgs.substring(0, spArgs.length()-1)); methodCLass = new StringBuilder(methodCLass.substring(0, methodCLass.length()-1)); } if(methodCLass.length()>0){ methodCLass.append("}"); } else{ methodCLass.append("new Class[0]"); } sp.append("){\n"); spArgs.append("}"); sp.append(spArgs+";\n"); if(sp.toString().contains("void")){ sp.append("try {\n this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n return;\n"); sp.append("} catch (Throwable e) {e.printStackTrace();}}"); } else{ sp.append("try {return " + "(" + m_.getReturnType().getName() + ")" + "this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n"); sp.append("} catch (Exception e) {e.printStackTrace();} return null;}"); } publicStaticMethods.append(methodCLass).append(");\n"); allMethods.append(sp); } } classsp = new StringBuilder(classsp.substring(0, classsp.length()-1)).append("{"); publicStaticMethods.append("} catch(Exception e){}}"); classsp.append(publicMethods) .append(publicStaticMethods) .append(constructorsp).append(allMethods).append(""); classsp.append("}"); importsp.append(classsp); return importsp.toString(); } public static void main(String[] args) throws Exception { System.out.println(mackMultiProxyClass(new Class<?>[]{Idto.class})); } }
看起来很复杂,仔细看一下就看了那么几个事情,把一个接口class或者多个接口class变成纯字符串的过程,一共两个方法,一个是单接口的实现,很早之前写的,第二个方法是多接口的实现支持多接口,只需要传一个class对象就会生成代理类的字符串,这里仅仅是字符串,需要编译成class使用。那么如何编译成class呢。通过java中的工具类 JavaCompiler很简单的就可以生成了。我们来看两个工具类实现
package meituan.zylproxy; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.Reader; import java.io.StringReader; import java.net.URI; import java.nio.CharBuffer; import java.nio.file.WatchEvent.Kind; import java.util.HashMap; import java.util.Map; import javax.tools.FileObject; import javax.tools.ForwardingJavaFileManager; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.SimpleJavaFileObject; @SuppressWarnings("unchecked") final class MemoryJavaFileManager extends ForwardingJavaFileManager { private final static String EXT = ".java"; private Map<String, byte[]> classBytes; public MemoryJavaFileManager(JavaFileManager fileManager) { super(fileManager); classBytes = new HashMap<String, byte[]>(); } public Map<String, byte[]> getClassBytes() { return classBytes; } public void close() throws IOException { classBytes = new HashMap<String, byte[]>(); } public void flush() throws IOException { } private static class StringInputBuffer extends SimpleJavaFileObject { final String code; StringInputBuffer(String name, String code) { super(toURI(name), Kind.SOURCE); this.code = code; } public CharBuffer getCharContent(boolean ignoreEncodingErrors) { return CharBuffer.wrap(code); } public Reader openReader() { return new StringReader(code); } } private class ClassOutputBuffer extends SimpleJavaFileObject { private String name; ClassOutputBuffer(String name) { super(toURI(name), Kind.CLASS); this.name = name; } public OutputStream openOutputStream() { return new FilterOutputStream(new ByteArrayOutputStream()) { public void close() throws IOException { out.close(); ByteArrayOutputStream bos = (ByteArrayOutputStream) out; classBytes.put(name, bos.toByteArray()); } }; } } public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException { if (kind == JavaFileObject.Kind.CLASS) { return new ClassOutputBuffer(className); } else { return super.getJavaFileForOutput(location, className, kind, sibling); } } static JavaFileObject makeStringSource(String name, String code) { return new StringInputBuffer(name, code); } static URI toURI(String name) { File file = new File(name); if (file.exists()) { return file.toURI(); } else { try { final StringBuilder newUri = new StringBuilder(); newUri.append("mfm:///"); newUri.append(name.replace('.', '/')); if (name.endsWith(EXT)) newUri.replace(newUri.length() - EXT.length(), newUri.length(), EXT); return URI.create(newUri.toString()); } catch (Exception exp) { return URI.create("mfm:///com/sun/script/java/java_source"); } } } }
package meituan.zylproxy; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; public class DynamicLoader { public static Map<String, byte[]> compile(String javaSrc) { Pattern pattern = Pattern.compile("public\\s+class\\s+(\\w+)"); Matcher matcher = pattern.matcher(javaSrc); if (matcher.find()) return compile(matcher.group(1) + ".java", javaSrc); return null; } public static Map<String, byte[]> compile(String javaName, String javaSrc) { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager stdManager = compiler.getStandardFileManager(null, null, null); try (MemoryJavaFileManager manager = new MemoryJavaFileManager(stdManager)) { JavaFileObject javaFileObject = manager.makeStringSource(javaName, javaSrc); JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, Arrays.asList(javaFileObject)); if (task.call()) return manager.getClassBytes(); } catch (IOException e) { e.printStackTrace(); } return null; } public static class MemoryClassLoader extends URLClassLoader { Map<String, byte[]> classBytes = new HashMap<String, byte[]>(); public MemoryClassLoader(Map<String, byte[]> classBytes) { super(new URL[0], MemoryClassLoader.class.getClassLoader()); this.classBytes.putAll(classBytes); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] buf = classBytes.get(name); if (buf == null) { return super.findClass(name); } classBytes.remove(name); return defineClass(name, buf, 0, buf.length); } } }
通过DynamicLoader的compile方法可以把纯字符串的str转成byte[]数组,有了byte[]数组就可以很方便的获取到class对象了,自定义一个MemoryClassLoader通过defineClass方法来获取到class对象。这样基本所有的事情都做完了。下面我们写一个工厂类来获取代理类。
package meituan.zylproxy.util; import java.util.Map; import meituan.zylproxy.DynamicLoader; import meituan.zylproxy.handlder.ZYLInvocationHandler; public class PorxyFactory { //单interface的时候用 public static Object newProxyInstance(Class<?> c,ZYLInvocationHandler h) throws Exception{ String classStr = ClassUtil.mackProxyClass(c); Map<String, byte[]> m = DynamicLoader.compile(classStr); DynamicLoader.MemoryClassLoader classLoader = new DynamicLoader.MemoryClassLoader(m); Class<?> proxy =classLoader.loadClass(m.keySet().toArray(new String[0])[0]); return proxy.getConstructor(ZYLInvocationHandler.class).newInstance(h); } //多interface的时候用 public static Object newProxyInstancewWithMultiClass(Class<?>[] c,ZYLInvocationHandler h) throws Exception{ String classStr = ClassUtil.mackMultiProxyClass(c); System.out.println (classStr); Map<String, byte[]> m = DynamicLoader.compile(classStr); DynamicLoader.MemoryClassLoader classLoader = new DynamicLoader.MemoryClassLoader(m); Class<?> proxy =classLoader.loadClass(m.keySet().toArray(new String[0])[0]); return proxy.getConstructor(ZYLInvocationHandler.class).newInstance(h); } }
最后一步我们测试一下结果吧,写一个测试类
package meituan.zylproxy.test; import meituan.zylproxy.handlder.Hander; import meituan.zylproxy.test.i.Idto; import meituan.zylproxy.test.i.impl.DtoImpl; import meituan.zylproxy.util.PorxyFactory; public class ZylPorxyTest { public static void main(String[] args) throws Exception { Idto d = (Idto) PorxyFactory.newProxyInstancewWithMultiClass(DtoImpl.class.getInterfaces(), new Hander(new DtoImpl())); d.add(); } }
很简单,第一个参数是所有的接口,第二个是handler实现。最后我们看看结果。
大功告成。
有更多的更多的源码交流,请加群825199617交流,spring源码,spring mvc源码,手写企业级高可用rpc框架等等更多精彩源码,等你来。