首页 > 编程语言 >【代理】【五】代理源码解析-Cglib代理-Enhancer代理对象创建过程

【代理】【五】代理源码解析-Cglib代理-Enhancer代理对象创建过程

时间:2023-03-04 14:23:05浏览次数:41  
标签:Enhancer ACC 代理 源码 new null type Constants

1  前言

上节我们看了 EnhancerKey 是通过KeyFactory里的  Generator来创建代理对象,这节我们就来看下 Enhancer是如何创建代理对象的。

2  源码分析

上节我们看过了,AbstractClassGenerator 是模板模式的枢纽,创建代理对象子类复写 generateClass 和 firstInstance两个方法即可。那么我们就来看下 Enhancer 里的是如何实现的。

2.1  generateClass 

public void generateClass(ClassVisitor v) throws Exception {
    // 就是我们的被代理类  Demo.class
    Class sc = (superclass == null) ? Object.class : superclass;
    // 看见没如果是final直接报错
    if (TypeUtils.isFinal(sc.getModifiers()))
        throw new IllegalArgumentException("Cannot subclass final class " + sc);
    // 构造器并过滤
    List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors()));
    filterConstructors(sc, constructors);
    // 收集方法
    List actualMethods = new ArrayList();
    List interfaceMethods = new ArrayList();
    final Set forcePublic = new HashSet();
    getMethods(sc, interfaces, actualMethods, interfaceMethods, forcePublic);
    // 权限过滤
    List methods = CollectionUtils.transform(actualMethods, new Transformer() {
        public Object transform(Object value) {
            Method method = (Method)value;
            int modifiers = Constants.ACC_FINAL
                | (method.getModifiers()
                   & ~Constants.ACC_ABSTRACT
                   & ~Constants.ACC_NATIVE
                   & ~Constants.ACC_SYNCHRONIZED);
            if (forcePublic.contains(MethodWrapper.create(method))) {
                modifiers = (modifiers & ~Constants.ACC_PROTECTED) | Constants.ACC_PUBLIC;
            }
            return ReflectUtils.getMethodInfo(method, modifiers);
        }
    });
    // ClassEmitter 对asm的classAdapter和MethodAdapter的实现,贯穿于cglib代码的处理
    // 理解成就是描述类的
    ClassEmitter e = new ClassEmitter(v);
    e.begin_class(Constants.V1_2,
                  Constants.ACC_PUBLIC,
                  getClassName(),
                  Type.getType(sc),
                  (useFactory ?
                   TypeUtils.add(TypeUtils.getTypes(interfaces), FACTORY) :
                   TypeUtils.getTypes(interfaces)),
                  Constants.SOURCE_FILE);
    List constructorInfo = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance());
    // 声明属性
    e.declare_field(Constants.ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null);
    if (!interceptDuringConstruction) {
        e.declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null);
    }
    e.declare_field(Constants.PRIVATE_FINAL_STATIC, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null);
    e.declare_field(Constants.PRIVATE_FINAL_STATIC, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null);
    if (serialVersionUID != null) {
        e.declare_field(Constants.PRIVATE_FINAL_STATIC, Constants.SUID_FIELD_NAME, Type.LONG_TYPE, serialVersionUID);
    }
    for (int i = 0; i < callbackTypes.length; i++) {
        e.declare_field(Constants.ACC_PRIVATE, getCallbackField(i), callbackTypes[i], null);
    }
    // 添加方法、构造器、等方法
    emitMethods(e, methods, actualMethods);
    emitConstructors(e, constructorInfo);
    emitSetThreadCallbacks(e);
    emitSetStaticCallbacks(e);
    emitBindCallbacks(e);
    // 这个就是你的代理要不要继承 Factory 可以更改你的增强逻辑
    if (useFactory) {
        int[] keys = getCallbackKeys();
        emitNewInstanceCallbacks(e);
        emitNewInstanceCallback(e);
        emitNewInstanceMultiarg(e, constructorInfo);
        emitGetCallback(e, keys);
        emitSetCallback(e, keys);
        emitGetCallbacks(e);
        emitSetCallbacks(e);
    }
    e.end_class();
}

上边在构造类的属性呀,方法什么的,其中一点我简单说下,有个 useFactory 不知道你发现没,默认是开启的,也就是开启的情况下我们的代理类会实现 Factory接口,那么这个接口是干啥的呢,我们来看下:

主要分三类方法,一类是获取设置的回调,也就是我们的增强的代码类,一类是创建代理对象,一类就是设置增强代码类,也就是说可以更改我们代理类的增强逻辑,我们来试下:

2.2  firstInstance

这个方法 firstInstance ,我们的增强逻辑也是在这个方法里塞进去的,我们来看下具体过程:

protected Object firstInstance(Class type) throws Exception {
    if (classOnly) {
        return type;
    } else {
// 进入这个方法 return createUsingReflection(type); } }
private Object createUsingReflection(Class type) {
    /**
     * type 是什么也就是我们代理类的类信息
     * 将我们的增强类设置进去
     * 然后创建出来代理对象后
     * 发现finally会清空掉类信息里的增强类 至于为什么 可能是保持类的干净?我猜的哈 有知道的可以告知下
     */
    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);
    }
}

ReflectUtils.newInstance 就是获取构造方法创建对象,这里就不看了哈。

3  小结

好这节我们大概看了下  Enhancer 对象创建代理对象的过程,主要就是 generateClass 和 firstInstance两个方法,有理解不对的地方欢迎指正哈。

标签:Enhancer,ACC,代理,源码,new,null,type,Constants
From: https://www.cnblogs.com/kukuxjx/p/17177172.html

相关文章

  • 反射与泛型、动态代理
    泛型在Java中的泛型简单来说就是:在创建对象或调⽤⽅法的时候才明确下具体的类型好处是:代码更加简洁(不再需要强制转换),程序更加健壮(在编译期间没有警告,在运⾏期就不会出现......
  • QT的Proxy Model(代理模型)
    在Qt中,ProxyModel(代理模型)是一种机制,可以让我们在不修改源数据的情况下,对数据进行排序、筛选、修改、隐藏、转换等操作。ProxyModel实际上是一种中间层,它将来自源模型的......
  • 【代理】【四】代理源码解析-Cglib代理-Generator代理对象创建过程
    1 前言 上节我们简单感受了下Cglib的一个代理过程,并且我也说到了Enhancer创建代理的时候,首先会创建对象Key出来,用于标识这个类以及将其作为缓存的Key,然后再创建代理对......
  • Apache设置反向代理解决js跨域问题
    这是一个很简单的方案,通过启用Apache反向代理解决js跨域问题为什么要这么做?在现在的开发过程中大家会遇到这样一个问题:后端代码写好之后,前端的小伙伴需要将后端代码部署......
  • 【代理】【三】代理源码解析-Cglib代理-环境准备以及简单介绍
    1 前言之前我们看过了JDK动态代理的源码了,今天我们大概花三四篇(因为一篇文章东西太多写的人费劲看的人也累哈)来看看Cglib的代理源码过程,其中涉及到asm包中的东西构建类......
  • 互联网医院源码搭建|互联网医院发展过程中遇到的问题
       互联网医疗分为互联网医院、互联网+医院两种模式,互联网+医院目前看已经算比较成熟了,几乎大的医院都是app或者公众号的预约、挂号、缴费、自助机一体化。目前真正难......
  • DK 动态代理和 CGLIB 动态代理的区别是什么?
    Java中实现动态代理有两种方式:JDK动态代理和CGLIB动态代理。动态代理的主要作用是在不改变原有代码的情况下,对原有代码进行增强。JDK动态代理JDK动态代理具体实现步骤:......
  • 代理异常捕获
    背景在某些场景,比如过滤器,拦截器,或者某些代理类的时候,ControllerAdvance是捕获不到异常的方案:使用springmvc框架,让程序直接导入进来//验证etbc登录try{......
  • 手把手教你使用LabVIEW人工智能视觉工具包快速实现传统Opencv算子的调用(含源码)
    (文章目录)前言今天我们一起来使用LabVIEWAI视觉工具包快速实现图像的滤波与增强;图像灰度处理;阈值处理与设定;二值化处理;边缘提取与特征提取等基本操作。工具包的安装与下......
  • 9_Spring_JDK动态代理
    ​ 代理模式是通过代理对象访问目标对象,这样可以在目标对象基础上增强额外的功能,如添加权限,访问控制和审计等功能。房产中介代替业主卖房 静态代理     ......