Cglib源码解析

  • Post author:
  • Post category:其他




1. 使用举例

public interface Calculator {
    public int add(int i, int j);
}


public class MyCglib implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Object o1 = methodProxy.invokeSuper(o, objects);
        return o1;
    }
}


public static void main(String[] args) {
        //动态代理创建的class文件存储到本地
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"d:\\code");
        //通过cglib动态代理获取代理对象的过程,创建调用的对象,在后续创建过程中EnhanceKey的对象,所以在进行enhancer对象创建的时候需要把EnhancerKey(newInstance)对象准备好,不过这个对象也需要动态代理来生成
        Enhancer enhancer = new Enhancer();
        //设置enhancer对象的父类
        enhancer.setSuperclass(MyCalculator.class);
        MyCglib myCglib = new MyCglib();
        //设置enhancer的回调对象
        enhancer.setCallback(myCglib);
        //创建代理对象
        MyCalculator myCalculator = (MyCalculator) enhancer.create();
        //通过代理对象调用目标方法
        int add = myCalculator.add(1, 1);
        System.out.println(myCalculator.getClass());
    }



2. 源码解析

public Object create() {
		classOnly = false;
		argumentTypes = null;
		return createHelper();
	}

private Object createHelper() {
		// 校验callbackTypes、filter是否为空,以及为空时的处理
		preValidate();
		// 通过newInstance方法来创建EnhancerKey对象,正常情况下,只需要new一个对象就可以调用方法了,
		// 但是Key_Factory是一个EnhancerKey类型,是一个内部接口,需要动态代理来实现,最终是为了调用newInstance方法
		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);
		// 设置当前enhancer的代理类的key标识
		this.currentKey = key;
		// 调用父类即AbstractClassGenerator的创建代理类
		Object result = super.create(key);
		return result;
	}

链接到

AbstractClassGenerator.java#create(key)

方法

protected Object create(Object key) {
		try {
			// 获取到当前生成器的类加载器
			ClassLoader loader = getClassLoader();
			// 当前类加载器对应的缓存  缓存key为类加载器,缓存的value为ClassLoaderData,可以理解为一个缓存对象,只不过此缓存对象中包含的是具体的业务逻辑处理过程,
			// 有两个function的函数式接口,一个是返回gen.key,对应的名称叫GET_KEY,还有一个是为了创建具体的class,名字叫做load
			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) {
						// 新建一个缓存Cache,并将之前的缓存Cache的数据添加进来,并将已经被gc回收的数据给清除掉
						Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
						// 新建一个当前加载器对应的ClassLoaderData并加到缓存中,但ClassLoaderData中此时还没有数据
						data = new ClassLoaderData(loader);
						newCache.put(loader, data);
						// 刷新全局缓存
						CACHE = newCache;
					}
				}
			}
			// 设置一个全局key
 			this.key = key;
			// 在刚创建的data(ClassLoaderData)中调用get方法 并将当前生成器,
			// 返回的是生成好的代理类的class信息;--》generatedClasses.get(gen);
            //其中generatedClasses包含两个Function;有两个构建好的回调。根据判断调用,最终达到生成字节码的目的。
			Object obj = data.get(this, getUseCache());
			// 如果为class则实例化class并返回我们需要的代理类
			if (obj instanceof Class) {
				return firstInstance((Class) obj);
			}
			// 如果不是则说明是实体,则直接执行另一个方法返回实体
			return nextInstance(obj);
		}
		catch (RuntimeException | Error ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new CodeGenerationException(ex);
		}
	}

上面代码注意

ClassLoaderData

类,是一个内部类

AbstractClasGenerator$ClassLoaderData

,其中比较重要的属性

generatedClasses

,是一个

LoadingCache

类型

public LoadingCache(Function<K, KK> keyMapper, Function<K, V> loader) {
        this.keyMapper = keyMapper;
        this.loader = loader;
        this.map = new ConcurrentHashMap();
    }

包含两个Function 类型的函数。

在这里插入图片描述

另外

ClassLoaderData

的代码如下:

	protected static class ClassLoaderData {

		private final Set<String> reservedClassNames = new HashSet<String>();

		private final LoadingCache<AbstractClassGenerator, Object, Object> generatedClasses;


		private final WeakReference<ClassLoader> classLoader;

		private final Predicate uniqueNamePredicate = new Predicate() {
			public boolean evaluate(Object name) {
				return reservedClassNames.contains(name);
			}
		};

        //核心代码,回调获取key
		private static final Function<AbstractClassGenerator, Object> GET_KEY = new Function<AbstractClassGenerator, Object>() {
			public Object apply(AbstractClassGenerator gen) {
				return gen.key;
			}
		};

        //注意这个构造方法,里面
		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);
						}
					};
			// 为这个ClassLoadData新建一个缓存类
			generatedClasses = new LoadingCache<AbstractClassGenerator, Object, Object>(GET_KEY, load);
		}

	 //...省略若干代码....
		public Object get(AbstractClassGenerator gen, boolean useCache) {
			// 如果不用缓存(默认使用)
			if (!useCache) {
				// 则直接调用生成器的命令
				return gen.generate(ClassLoaderData.this);
			}
			else {
				// 传入代理类生成器 并根据代理类生成器获取值返回
				Object cachedValue = generatedClasses.get(gen);
				// 解包装并返回
				return gen.unwrapCachedValue(cachedValue);
			}
		}
	}



总结

主要是需要生成字节码。

LoadingCache

中放入了两个

Function

函数,通过回调的形式,一个获取key,一个根据上面的key获取字节码对象。


部分字节码展示

  
  public final int add(int paramInt1, int paramInt2) {
    if (this.CGLIB$CALLBACK_0 == null)
      CGLIB$BIND_CALLBACKS(this); 
    if (this.CGLIB$CALLBACK_0 != null) {
      this.CGLIB$CALLBACK_0.intercept(this, CGLIB$add$0$Method, new Object[] { new Integer(paramInt1), new Integer(paramInt2) }, CGLIB$add$0$Proxy);
      return (this.CGLIB$CALLBACK_0.intercept(this, CGLIB$add$0$Method, new Object[] { new Integer(paramInt1), new Integer(paramInt2) }, CGLIB$add$0$Proxy) == null) ? 0 : ((Number)this.CGLIB$CALLBACK_0.intercept(this, CGLIB$add$0$Method, new Object[] { new Integer(paramInt1), new Integer(paramInt2) }, CGLIB$add$0$Proxy)).intValue();
    } 
    return super.add(paramInt1, paramInt2);
  }

可以看到callBack 不为空的话,那么调用intercept。继而调用到FastClass 中的方法。

在这里插入图片描述



版权声明:本文为sbl19940819原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。